Bug 1446961, move PopupBoxObject to XULPopupElement, a new subclass of XULElement. Remove popup.xml methods, r=paolo,bz

Test changes for removal of PopupBoxObject and popup.xml methods, some reflow tests now have different stacks now that they are not going through popup.xml binding methods, test_popupanchor.xul changes due to need to wait for popuppositioned event after resizing. The old code would just adjust the arrow directly when sizeTo was called, but the new code does this through an asynchronous popuppositioned event. Changes to some places that check for XULElement class.

--HG--
rename : dom/webidl/PopupBoxObject.webidl => dom/webidl/XULPopupElement.webidl
rename : layout/xul/PopupBoxObject.cpp => dom/xul/XULPopupElement.cpp
rename : layout/xul/PopupBoxObject.h => dom/xul/XULPopupElement.h
This commit is contained in:
Neil Deakin 2018-04-27 11:04:38 -04:00
parent 8fc4678d7a
commit ef5f9b4b23
23 changed files with 223 additions and 423 deletions

View File

@ -16,14 +16,12 @@ let gCUITestUtils = new CustomizableUITestUtils(window);
const EXPECTED_APPMENU_OPEN_REFLOWS = [
{
stack: [
"openPopup@chrome://global/content/bindings/popup.xml",
"openPopup/this._openPopupPromise<@resource:///modules/PanelMultiView.jsm",
],
},
{
stack: [
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
"onxblpopuppositioned@chrome://global/content/bindings/popup.xml",
],
@ -31,21 +29,13 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
maxCount: 3, // This number should only ever go down - never up.
},
{
stack: [
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
"_calculateMaxHeight@resource:///modules/PanelMultiView.jsm",
"handleEvent@resource:///modules/PanelMultiView.jsm",
],
},
{
stack: [
"_calculateMaxHeight@resource:///modules/PanelMultiView.jsm",
"handleEvent@resource:///modules/PanelMultiView.jsm",
],
maxCount: 6, // This number should only ever go down - never up.
maxCount: 7, // This number should only ever go down - never up.
},
];

View File

@ -23,7 +23,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
"enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/popup.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
@ -74,7 +73,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
// Bug 1359989
{
stack: [
"openPopup@chrome://global/content/bindings/popup.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",

View File

@ -23,7 +23,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
"enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/popup.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
@ -74,7 +73,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
// Bug 1359989
{
stack: [
"openPopup@chrome://global/content/bindings/popup.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
@ -116,7 +114,6 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
// Bug 1359989
{
stack: [
"openPopup@chrome://global/content/bindings/popup.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",

View File

@ -408,7 +408,7 @@ const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
let url = "";
// If the listener is an object with a 'handleEvent' method, use that.
if (listenerDO.class === "Object" || listenerDO.class === "XULElement") {
if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
let desc;
while (!desc && listenerDO) {

View File

@ -1146,7 +1146,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// Get the Debugger.Object for the listener object.
let listenerDO = this.globalDebugObject.makeDebuggeeValue(listener);
// If the listener is an object with a 'handleEvent' method, use that.
if (listenerDO.class == "Object" || listenerDO.class == "XULElement") {
if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
// For some events we don't have permission to access the
// 'handleEvent' property when running in content scope.
if (!listenerDO.unwrap()) {

View File

@ -256,7 +256,6 @@
#ifdef MOZ_XUL
#include "mozilla/dom/ListBoxObject.h"
#include "mozilla/dom/MenuBoxObject.h"
#include "mozilla/dom/PopupBoxObject.h"
#include "mozilla/dom/ScrollBoxObject.h"
#include "mozilla/dom/TreeBoxObject.h"
#endif
@ -6576,11 +6575,6 @@ nsIDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv)
if (namespaceID == kNameSpaceID_XUL) {
if (tag == nsGkAtoms::menu) {
boxObject = new MenuBoxObject();
} else if (tag == nsGkAtoms::popup ||
tag == nsGkAtoms::menupopup ||
tag == nsGkAtoms::panel ||
tag == nsGkAtoms::tooltip) {
boxObject = new PopupBoxObject();
} else if (tag == nsGkAtoms::tree) {
boxObject = new TreeBoxObject();
} else if (tag == nsGkAtoms::listbox) {

View File

@ -107,10 +107,6 @@ DOMInterfaces = {
'headerFile': 'BatteryManager.h'
},
'BoxObject': {
'resultNotAddRefed': ['element'],
},
'Cache': {
'implicitJSContext': [ 'add', 'addAll', 'match', 'matchAll', 'put',
'delete', 'keys' ],
@ -691,10 +687,6 @@ DOMInterfaces = {
'nativeType': 'nsIPluginTag',
},
'PopupBoxObject': {
'resultNotAddRefed': ['triggerNode', 'anchorNode'],
},
'Position': {
'headerFile': 'nsGeoPosition.h'
},

View File

@ -788,8 +788,6 @@ var interfaceNamesInGlobalScope =
{name: "PopStateEvent", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PopupBlockedEvent", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PopupBoxObject", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "Presentation", insecureContext: true, desktop: false, release: false },
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -1268,6 +1266,8 @@ var interfaceNamesInGlobalScope =
{name: "XULDocument", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULElement", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULPopupElement", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
];
// IMPORTANT: Do not change the list above without review from a DOM peer!

View File

@ -20,8 +20,8 @@ dictionary OpenPopupOptions {
typedef (DOMString or OpenPopupOptions) StringOrOpenPopupOptions;
[Func="IsChromeOrXBL"]
interface PopupBoxObject : BoxObject
[HTMLConstructor, Func="IsChromeOrXBL"]
interface XULPopupElement : XULElement
{
/**
* Allow the popup to automatically position itself.
@ -84,9 +84,9 @@ interface PopupBoxObject : BoxObject
* @param y vertical screen position
* @param triggerEvent the event that triggered this popup (mouse click for example)
*/
void openPopupAtScreen(long x, long y,
boolean isContextMenu,
Event? triggerEvent);
void openPopupAtScreen(optional long x = 0, optional long y = 0,
optional boolean isContextMenu = false,
optional Event? triggerEvent = null);
/**
* Open the popup anchored at a specific screen rectangle. This function is
@ -95,13 +95,13 @@ interface PopupBoxObject : BoxObject
* coordinates.
*/
void openPopupAtScreenRect(optional DOMString position = "",
long x,
long y,
long width,
long height,
boolean isContextMenu,
boolean attributesOverride,
Event? triggerEvent);
optional long x = 0,
optional long y = 0,
optional long width = 0,
optional long height = 0,
optional boolean isContextMenu = false,
optional boolean attributesOverride = false,
optional Event? triggerEvent = null);
/**
* Hide the popup if it is open. The cancel argument is used as a hint that
@ -112,6 +112,18 @@ interface PopupBoxObject : BoxObject
*/
void hidePopup(optional boolean cancel = false);
/**
* Attribute getter and setter for label.
*/
[SetterThrows]
attribute DOMString label;
/**
* Attribute getter and setter for position.
*/
[SetterThrows]
attribute DOMString position;
/**
* Returns the state of the popup:
* closed - the popup is closed
@ -119,7 +131,7 @@ interface PopupBoxObject : BoxObject
* showing - the popup is in the process of being shown
* hiding - the popup is in the process of being hidden
*/
readonly attribute DOMString popupState;
readonly attribute DOMString state;
/**
* The node that triggered the popup. If the popup is not open, will return
@ -149,10 +161,10 @@ interface PopupBoxObject : BoxObject
* meaning as the corresponding argument to openPopup. This method has no effect
* on popups that are not open.
*/
void moveToAnchor(Element? anchorElement,
void moveToAnchor(optional Element? anchorElement = null,
optional DOMString position = "",
long x, long y,
boolean attributesOverride);
optional long x = 0, optional long y = 0,
optional boolean attributesOverride = false);
/**
* Size the popup to the given dimensions

View File

@ -721,7 +721,6 @@ WEBIDL_FILES = [
'Plugin.webidl',
'PluginArray.webidl',
'PointerEvent.webidl',
'PopupBoxObject.webidl',
'Position.webidl',
'PositionError.webidl',
'Presentation.webidl',
@ -953,6 +952,7 @@ WEBIDL_FILES = [
'XULCommandEvent.webidl',
'XULDocument.webidl',
'XULElement.webidl',
'XULPopupElement.webidl',
]
if CONFIG['MOZ_WEBRTC']:

View File

@ -14,48 +14,46 @@
#include "nsView.h"
#include "mozilla/AppUnits.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/PopupBoxObject.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/PopupBoxObjectBinding.h"
#include "mozilla/dom/XULPopupElement.h"
#include "mozilla/dom/XULPopupElementBinding.h"
namespace mozilla {
namespace dom {
PopupBoxObject::PopupBoxObject()
nsXULElement*
NS_NewXULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
{
return new XULPopupElement(aNodeInfo);
}
PopupBoxObject::~PopupBoxObject()
JSObject*
XULPopupElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
return XULPopupElementBinding::Wrap(aCx, this, aGivenProto);
}
nsIContent* PopupBoxObject::GetParentObject() const
nsIFrame*
XULPopupElement::GetFrame(bool aFlushLayout)
{
return BoxObject::GetParentObject();
}
nsCOMPtr<nsIContent> kungFuDeathGrip = this; // keep a reference
JSObject* PopupBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PopupBoxObjectBinding::Wrap(aCx, this, aGivenProto);
}
void
PopupBoxObject::HidePopup(bool aCancel)
{
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mContent) {
pm->HidePopup(mContent, false, true, false, aCancel);
nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
if (doc) {
doc->FlushPendingNotifications(aFlushLayout ? FlushType::Layout : FlushType::Frames);
}
return GetPrimaryFrame();
}
void
PopupBoxObject::OpenPopup(Element* aAnchorElement,
const StringOrOpenPopupOptions& aOptions,
int32_t aXPos, int32_t aYPos,
bool aIsContextMenu,
bool aAttributesOverride,
Event* aTriggerEvent)
XULPopupElement::OpenPopup(Element* aAnchorElement,
const StringOrOpenPopupOptions& aOptions,
int32_t aXPos, int32_t aYPos,
bool aIsContextMenu,
bool aAttributesOverride,
Event* aTriggerEvent)
{
nsAutoString position;
if (aOptions.IsOpenPopupOptions()) {
@ -72,107 +70,109 @@ PopupBoxObject::OpenPopup(Element* aAnchorElement,
}
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mContent) {
if (pm) {
// As a special case for popups that are menus when no anchor or position are
// specified, open the popup with ShowMenu instead of ShowPopup so that the
// popup is aligned with the menu.
if (!aAnchorElement && position.IsEmpty() && mContent->GetPrimaryFrame()) {
nsMenuFrame* menu = do_QueryFrame(mContent->GetPrimaryFrame()->GetParent());
if (!aAnchorElement && position.IsEmpty() && GetPrimaryFrame()) {
nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame()->GetParent());
if (menu) {
pm->ShowMenu(menu->GetContent(), false, false);
return;
}
}
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
pm->ShowPopup(mContent, anchorContent, position, aXPos, aYPos,
pm->ShowPopup(this, aAnchorElement, position, aXPos, aYPos,
aIsContextMenu, aAttributesOverride, false, aTriggerEvent);
}
}
void
PopupBoxObject::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
bool aIsContextMenu,
Event* aTriggerEvent)
XULPopupElement::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
bool aIsContextMenu,
Event* aTriggerEvent)
{
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mContent)
pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
if (pm) {
pm->ShowPopupAtScreen(this, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
}
}
void
PopupBoxObject::OpenPopupAtScreenRect(const nsAString& aPosition,
int32_t aXPos, int32_t aYPos,
int32_t aWidth, int32_t aHeight,
bool aIsContextMenu,
bool aAttributesOverride,
Event* aTriggerEvent)
XULPopupElement::OpenPopupAtScreenRect(const nsAString& aPosition,
int32_t aXPos, int32_t aYPos,
int32_t aWidth, int32_t aHeight,
bool aIsContextMenu,
bool aAttributesOverride,
Event* aTriggerEvent)
{
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mContent) {
pm->ShowPopupAtScreenRect(mContent, aPosition,
if (pm) {
pm->ShowPopupAtScreenRect(this, aPosition,
nsIntRect(aXPos, aYPos, aWidth, aHeight),
aIsContextMenu, aAttributesOverride, aTriggerEvent);
}
}
void
PopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop)
XULPopupElement::HidePopup(bool aCancel)
{
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
pm->HidePopup(this, false, true, false, aCancel);
}
}
void
XULPopupElement::MoveTo(int32_t aLeft, int32_t aTop)
{
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame) {
menuPopupFrame->MoveTo(CSSIntPoint(aLeft, aTop), true);
}
}
void
PopupBoxObject::MoveToAnchor(Element* aAnchorElement,
const nsAString& aPosition,
int32_t aXPos, int32_t aYPos,
bool aAttributesOverride)
XULPopupElement::MoveToAnchor(Element* aAnchorElement,
const nsAString& aPosition,
int32_t aXPos, int32_t aYPos,
bool aAttributesOverride)
{
if (mContent) {
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (menuPopupFrame && menuPopupFrame->IsVisible()) {
menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
}
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame && menuPopupFrame->IsVisible()) {
menuPopupFrame->MoveToAnchor(aAnchorElement, aPosition, aXPos, aYPos, aAttributesOverride);
}
}
void
PopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
XULPopupElement::SizeTo(int32_t aWidth, int32_t aHeight)
{
if (!mContent)
return;
nsAutoString width, height;
width.AppendInt(aWidth);
height.AppendInt(aHeight);
RefPtr<Element> element = mContent->AsElement();
nsCOMPtr<nsIContent> kungFuDeathGrip = this; // keep a reference
// We only want to pass aNotify=true to SetAttr once, but must make sure
// we pass it when a value is being changed. Thus, we check if the height
// is the same and if so, pass true when setting the width.
bool heightSame = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
bool heightSame = AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
element->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
element->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
// If the popup is open, force a reposition of the popup after resizing it
// with notifications set to true so that the popuppositioned event is fired.
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupShown) {
menuPopupFrame->SetPopupPosition(nullptr, false, false, true);
}
}
bool
PopupBoxObject::AutoPosition()
XULPopupElement::AutoPosition()
{
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame) {
return menuPopupFrame->GetAutoPosition();
}
@ -180,21 +180,21 @@ PopupBoxObject::AutoPosition()
}
void
PopupBoxObject::SetAutoPosition(bool aShouldAutoPosition)
XULPopupElement::SetAutoPosition(bool aShouldAutoPosition)
{
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame) {
menuPopupFrame->SetAutoPosition(aShouldAutoPosition);
}
}
void
PopupBoxObject::GetPopupState(nsString& aState)
XULPopupElement::GetState(nsString& aState)
{
// set this here in case there's no frame for the popup
aState.AssignLiteral("closed");
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (menuPopupFrame) {
switch (menuPopupFrame->PopupState()) {
case ePopupShown:
@ -220,16 +220,16 @@ PopupBoxObject::GetPopupState(nsString& aState)
}
nsINode*
PopupBoxObject::GetTriggerNode() const
XULPopupElement::GetTriggerNode() const
{
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
return nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
}
Element*
PopupBoxObject::GetAnchorNode() const
XULPopupElement::GetAnchorNode() const
{
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
if (!menuPopupFrame) {
return nullptr;
}
@ -239,9 +239,9 @@ PopupBoxObject::GetAnchorNode() const
}
already_AddRefed<DOMRect>
PopupBoxObject::GetOuterScreenRect()
XULPopupElement::GetOuterScreenRect()
{
RefPtr<DOMRect> rect = new DOMRect(mContent);
RefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
// Return an empty rectangle if the popup is not open.
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
@ -263,7 +263,7 @@ PopupBoxObject::GetOuterScreenRect()
}
void
PopupBoxObject::GetAlignmentPosition(nsString& positionStr)
XULPopupElement::GetAlignmentPosition(nsString& positionStr)
{
positionStr.Truncate();
@ -314,7 +314,7 @@ PopupBoxObject::GetAlignmentPosition(nsString& positionStr)
}
int32_t
PopupBoxObject::AlignmentOffset()
XULPopupElement::AlignmentOffset()
{
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
if (!menuPopupFrame)
@ -330,7 +330,7 @@ PopupBoxObject::AlignmentOffset()
}
void
PopupBoxObject::SetConstraintRect(dom::DOMRectReadOnly& aRect)
XULPopupElement::SetConstraintRect(dom::DOMRectReadOnly& aRect)
{
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
if (menuPopupFrame) {
@ -341,13 +341,3 @@ PopupBoxObject::SetConstraintRect(dom::DOMRectReadOnly& aRect)
} // namespace dom
} // namespace mozilla
// Creation Routine ///////////////////////////////////////////////////////////////////////
nsresult
NS_NewPopupBoxObject(nsIBoxObject** aResult)
{
*aResult = new mozilla::dom::PopupBoxObject();
NS_ADDREF(*aResult);
return NS_OK;
}

View File

@ -4,15 +4,15 @@
* 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/. */
#ifndef mozilla_dom_PopupBoxObject_h
#define mozilla_dom_PopupBoxObject_h
#ifndef XULPopupElement_h__
#define XULPopupElement_h__
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/BoxObject.h"
#include "nsString.h"
#include "nsXULElement.h"
struct JSContext;
@ -24,22 +24,44 @@ class Element;
class Event;
class StringOrOpenPopupOptions;
class PopupBoxObject final : public BoxObject
nsXULElement*
NS_NewXULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
class XULPopupElement final : public nsXULElement
{
private:
nsIFrame* GetFrame(bool aFlushLayout);
public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(PopupBoxObject, BoxObject)
explicit XULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsXULElement(aNodeInfo)
{
}
PopupBoxObject();
void GetLabel(DOMString& aValue) const
{
GetXULAttr(nsGkAtoms::label, aValue);
}
void SetLabel(const nsAString& aValue, ErrorResult& rv)
{
SetXULAttr(nsGkAtoms::label, aValue, rv);
}
nsIContent* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetPosition(DOMString& aValue) const
{
GetXULAttr(nsGkAtoms::position, aValue);
}
void SetPosition(const nsAString& aValue, ErrorResult& rv)
{
SetXULAttr(nsGkAtoms::position, aValue, rv);
}
bool AutoPosition();
void SetAutoPosition(bool aShouldAutoPosition);
void OpenPopup(Element* aAnchorElement,
const mozilla::dom::StringOrOpenPopupOptions& aOptions,
const StringOrOpenPopupOptions& aOptions,
int32_t aXPos,
int32_t aYPos,
bool aIsContextMenu, bool aAttributesOverride,
@ -59,7 +81,7 @@ public:
void HidePopup(bool aCancel);
void GetPopupState(nsString& aState);
void GetState(nsString& aState);
nsINode* GetTriggerNode() const;
@ -81,13 +103,17 @@ public:
int32_t AlignmentOffset();
void SetConstraintRect(dom::DOMRectReadOnly& aRect);
void SetConstraintRect(DOMRectReadOnly& aRect);
private:
~PopupBoxObject();
protected:
virtual ~XULPopupElement()
{
}
JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PopupBoxObject_h
#endif // XULPopupElement_h

View File

@ -23,6 +23,10 @@ if CONFIG['MOZ_XUL']:
'nsXULElement.h',
]
EXPORTS.mozilla.dom += [
'XULPopupElement.h',
]
UNIFIED_SOURCES += [
'nsXULCommandDispatcher.cpp',
'nsXULContentSink.cpp',
@ -33,6 +37,7 @@ if CONFIG['MOZ_XUL']:
'nsXULPrototypeDocument.cpp',
'nsXULSortService.cpp',
'XULDocument.cpp',
'XULPopupElement.cpp',
]
XPIDL_SOURCES += [

View File

@ -75,6 +75,7 @@
#include "nsCCUncollectableMarker.h"
#include "nsICSSDeclaration.h"
#include "nsLayoutUtils.h"
#include "XULPopupElement.h"
#include "mozilla/dom/XULElementBinding.h"
#include "mozilla/dom/BoxObject.h"
@ -170,9 +171,14 @@ nsXULElement* NS_NewBasicXULElement(already_AddRefed<mozilla::dom::NodeInfo>&& a
/* static */
nsXULElement* nsXULElement::Construct(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
{
// Check tagname and create other types of elements here
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
if (nodeInfo->Equals(nsGkAtoms::menupopup) ||
nodeInfo->Equals(nsGkAtoms::popup) ||
nodeInfo->Equals(nsGkAtoms::panel) ||
nodeInfo->Equals(nsGkAtoms::tooltip)) {
return NS_NewXULPopupElement(nodeInfo.forget());
}
return NS_NewBasicXULElement(nodeInfo.forget());
}

View File

@ -332,8 +332,8 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
#undef XUL_ELEMENT_FLAG_BIT
class nsXULElement final : public nsStyledElement,
public nsIDOMNode
class nsXULElement : public nsStyledElement,
public nsIDOMNode
{
protected:
// Use Construct to construct elements instead of this constructor.

View File

@ -31,10 +31,6 @@
#define NS_MENUBOXOBJECT_CID \
{ 0xaa40253b, 0x4c42, 0x4056, { 0x81, 0x32, 0x37, 0xbc, 0xd0, 0x78, 0x62, 0xfd } }
// {6C392C62-1AB1-4de7-BFC6-ED4F9FC7749A}
#define NS_POPUPBOXOBJECT_CID \
{ 0x6c392c62, 0x1ab1, 0x4de7, { 0xbf, 0xc6, 0xed, 0x4f, 0x9f, 0xc7, 0x74, 0x9a } }
// {3B581FD4-3497-426c-8F61-3658B971CB80}
#define NS_TREEBOXOBJECT_CID \
{ 0x3b581fd4, 0x3497, 0x426c, { 0x8f, 0x61, 0x36, 0x58, 0xb9, 0x71, 0xcb, 0x80 } }

View File

@ -304,7 +304,6 @@ nsresult NS_NewBoxObject(nsIBoxObject** aResult);
nsresult NS_NewListBoxObject(nsIBoxObject** aResult);
nsresult NS_NewScrollBoxObject(nsIBoxObject** aResult);
nsresult NS_NewMenuBoxObject(nsIBoxObject** aResult);
nsresult NS_NewPopupBoxObject(nsIBoxObject** aResult);
nsresult NS_NewTreeBoxObject(nsIBoxObject** aResult);
#endif
@ -366,7 +365,6 @@ MAKE_CTOR(CreateNewBoxObject, nsIBoxObject, NS_NewBoxObject)
#ifdef MOZ_XUL
MAKE_CTOR(CreateNewListBoxObject, nsIBoxObject, NS_NewListBoxObject)
MAKE_CTOR(CreateNewMenuBoxObject, nsIBoxObject, NS_NewMenuBoxObject)
MAKE_CTOR(CreateNewPopupBoxObject, nsIBoxObject, NS_NewPopupBoxObject)
MAKE_CTOR(CreateNewScrollBoxObject, nsIBoxObject, NS_NewScrollBoxObject)
MAKE_CTOR(CreateNewTreeBoxObject, nsIBoxObject, NS_NewTreeBoxObject)
#endif // MOZ_XUL
@ -509,7 +507,6 @@ NS_DEFINE_NAMED_CID(NS_BOXOBJECT_CID);
#ifdef MOZ_XUL
NS_DEFINE_NAMED_CID(NS_LISTBOXOBJECT_CID);
NS_DEFINE_NAMED_CID(NS_MENUBOXOBJECT_CID);
NS_DEFINE_NAMED_CID(NS_POPUPBOXOBJECT_CID);
NS_DEFINE_NAMED_CID(NS_SCROLLBOXOBJECT_CID);
NS_DEFINE_NAMED_CID(NS_TREEBOXOBJECT_CID);
#endif // MOZ_XUL
@ -751,7 +748,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
#ifdef MOZ_XUL
{ &kNS_LISTBOXOBJECT_CID, false, nullptr, CreateNewListBoxObject },
{ &kNS_MENUBOXOBJECT_CID, false, nullptr, CreateNewMenuBoxObject },
{ &kNS_POPUPBOXOBJECT_CID, false, nullptr, CreateNewPopupBoxObject },
{ &kNS_SCROLLBOXOBJECT_CID, false, nullptr, CreateNewScrollBoxObject },
{ &kNS_TREEBOXOBJECT_CID, false, nullptr, CreateNewTreeBoxObject },
#endif // MOZ_XUL
@ -859,7 +855,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
#ifdef MOZ_XUL
{ "@mozilla.org/layout/xul-boxobject-listbox;1", &kNS_LISTBOXOBJECT_CID },
{ "@mozilla.org/layout/xul-boxobject-menu;1", &kNS_MENUBOXOBJECT_CID },
{ "@mozilla.org/layout/xul-boxobject-popup;1", &kNS_POPUPBOXOBJECT_CID },
{ "@mozilla.org/layout/xul-boxobject-scrollbox;1", &kNS_SCROLLBOXOBJECT_CID },
{ "@mozilla.org/layout/xul-boxobject-tree;1", &kNS_TREEBOXOBJECT_CID },
#endif // MOZ_XUL

View File

@ -35,7 +35,6 @@ EXPORTS.mozilla.dom += [
'BoxObject.h',
'ListBoxObject.h',
'MenuBoxObject.h',
'PopupBoxObject.h',
'ScrollBoxObject.h',
]
@ -82,7 +81,6 @@ if CONFIG['MOZ_XUL']:
'nsTitleBarFrame.cpp',
'nsXULLabelFrame.cpp',
'nsXULPopupManager.cpp',
'PopupBoxObject.cpp',
'ScrollBoxObject.cpp',
]

View File

@ -2287,7 +2287,7 @@ nsMenuPopupFrame::MoveToAttributePosition()
// Move the widget around when the user sets the |left| and |top| attributes.
// Note that this is not the best way to move the widget, as it results in lots
// of FE notifications and is likely to be slow as molasses. Use |moveTo| on
// PopupBoxObject if possible.
// the element if possible.
nsAutoString left, top;
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::left, left);
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::top, top);

View File

@ -444,7 +444,7 @@ public:
/**
* Open a popup, either anchored or unanchored. If aSelectFirstItem is
* true, then the first item in the menu is selected. The arguments are
* similar to those for nsIPopupBoxObject::OpenPopup.
* similar to those for XULPopupElement::OpenPopup.
*
* aTriggerEvent should be the event that triggered the event. This is used
* to determine the coordinates and trigger node for the popup. This may be

View File

@ -151,22 +151,26 @@ var tests = [
next();
});
}],
['flippingResizeHorizontal', 'middle', function(next) {
openPopup("after_end", function() {
isArrowPositionedOn("right");
panel.sizeTo(anchor.getBoundingClientRect().left + 50, 50);
isArrowPositionedOn("left"); // check it flipped and has zero offset.
next();
waitForPopupPositioned(
() => { panel.sizeTo(anchor.getBoundingClientRect().left + 50, 50); },
() => {
isArrowPositionedOn("left"); // check it flipped and has zero offset.
next();
});
});
}],
['flippingResizeVertical', 'middle', function(next) {
openPopup("start_after", function() {
isArrowPositionedOn("bottom");
panel.sizeTo(50, anchor.getBoundingClientRect().top + 50);
isArrowPositionedOn("top"); // check it flipped and has zero offset.
next();
waitForPopupPositioned(
() => { panel.sizeTo(50, anchor.getBoundingClientRect().top + 50); },
() => {
isArrowPositionedOn("top"); // check it flipped and has zero offset.
next();
});
});
}],
@ -271,13 +275,16 @@ var tests = [
// Now move it such that the arrow can't be at either end of the panel but
// instead somewhere in the middle as that is the only way things fit,
// meaning the arrow should "slide" down the panel.
panel.sizeTo(window.innerWidth - 10, 60);
is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested.")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
waitForPopupPositioned(
() => { panel.sizeTo(window.innerWidth - 10, 60); },
() => {
is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested.")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
});
});
}],
@ -286,13 +293,16 @@ var tests = [
var origArrowRect = arrow.getBoundingClientRect();
// Now size it such that the arrow can't be at either end of the panel but
// instead somewhere in the middle as that is the only way things fit.
panel.sizeTo(window.innerWidth - 10, 60);
is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
waitForPopupPositioned(
() => { panel.sizeTo(window.innerWidth - 10, 60); },
() => {
is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
});
});
}],
@ -302,13 +312,16 @@ var tests = [
// Now move it such that the arrow can't be at either end of the panel but
// instead somewhere in the middle as that is the only way things fit,
// meaning the arrow should "slide" down the panel.
panel.sizeTo(100, window.innerHeight - 10);
is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested.")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
waitForPopupPositioned(
() => { panel.sizeTo(100, window.innerHeight - 10); },
() => {
is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested.")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
});
});
}],
@ -317,13 +330,16 @@ var tests = [
var origArrowRect = arrow.getBoundingClientRect();
// Now size it such that the arrow can't be at either end of the panel but
// instead somewhere in the middle as that is the only way things fit.
panel.sizeTo(100, window.innerHeight - 10);
is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
waitForPopupPositioned(
() => { panel.sizeTo(100, window.innerHeight - 10); },
() => {
is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested")
// the arrow should not have moved.
var curArrowRect = arrow.getBoundingClientRect();
is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
next();
});
});
}],

View File

@ -15,197 +15,6 @@
<resources>
<stylesheet src="chrome://global/skin/popup.css"/>
</resources>
<implementation>
<property name="label" onget="return this.getAttribute('label');"
onset="this.setAttribute('label', val); return val;"/>
<property name="position" onget="return this.getAttribute('position');"
onset="this.setAttribute('position', val); return val;"/>
<property name="popupBoxObject">
<getter>
return this.boxObject;
</getter>
</property>
<property name="state" readonly="true"
onget="return this.popupBoxObject.popupState"/>
<property name="triggerNode" readonly="true"
onget="return this.popupBoxObject.triggerNode"/>
<property name="anchorNode" readonly="true"
onget="return this.popupBoxObject.anchorNode"/>
<method name="openPopup">
<parameter name="aAnchorElement"/>
<parameter name="aPosition"/>
<parameter name="aX"/>
<parameter name="aY"/>
<parameter name="aIsContextMenu"/>
<parameter name="aAttributesOverride"/>
<parameter name="aTriggerEvent"/>
<body>
<![CDATA[
// Allow for passing an options object as the second argument.
if (arguments.length == 2 &&
arguments[1] != null &&
typeof arguments[1] == "object") {
let params = arguments[1];
aPosition = params.position;
aX = params.x;
aY = params.y;
aIsContextMenu = params.isContextMenu;
aAttributesOverride = params.attributesOverride;
aTriggerEvent = params.triggerEvent;
}
try {
var popupBox = this.popupBoxObject;
if (popupBox)
popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
aIsContextMenu, aAttributesOverride, aTriggerEvent);
} catch (e) {}
]]>
</body>
</method>
<method name="openPopupAtScreen">
<parameter name="aX"/>
<parameter name="aY"/>
<parameter name="aIsContextMenu"/>
<parameter name="aTriggerEvent"/>
<body>
<![CDATA[
try {
var popupBox = this.popupBoxObject;
if (popupBox)
popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
} catch (e) {}
]]>
</body>
</method>
<method name="openPopupAtScreenRect">
<parameter name="aPosition"/>
<parameter name="aX"/>
<parameter name="aY"/>
<parameter name="aWidth"/>
<parameter name="aHeight"/>
<parameter name="aIsContextMenu"/>
<parameter name="aAttributesOverride"/>
<parameter name="aTriggerEvent"/>
<body>
<![CDATA[
try {
var popupBox = this.popupBoxObject;
if (popupBox)
popupBox.openPopupAtScreenRect(aPosition, aX, aY, aWidth, aHeight,
aIsContextMenu, aAttributesOverride, aTriggerEvent);
} catch (e) {}
]]>
</body>
</method>
<method name="hidePopup">
<parameter name="cancel"/>
<body>
<![CDATA[
var popupBox = null;
var menuBox = null;
try {
popupBox = this.popupBoxObject;
} catch (e) {}
try {
menuBox = this.parentNode.boxObject;
} catch (e) {}
if (menuBox instanceof MenuBoxObject)
menuBox.openMenu(false);
else if (popupBox instanceof PopupBoxObject)
popupBox.hidePopup(cancel);
]]>
</body>
</method>
<property name="autoPosition">
<getter>
<![CDATA[
return this.popupBoxObject.autoPosition;
]]>
</getter>
<setter>
<![CDATA[
return this.popupBoxObject.autoPosition = val;
]]>
</setter>
</property>
<property name="alignmentPosition" readonly="true">
<getter>
<![CDATA[
return this.popupBoxObject.alignmentPosition;
]]>
</getter>
</property>
<property name="alignmentOffset" readonly="true">
<getter>
<![CDATA[
return this.popupBoxObject.alignmentOffset;
]]>
</getter>
</property>
<method name="moveTo">
<parameter name="aLeft"/>
<parameter name="aTop"/>
<body>
<![CDATA[
this.popupBoxObject.moveTo(aLeft, aTop);
]]>
</body>
</method>
<method name="moveToAnchor">
<parameter name="aAnchorElement"/>
<parameter name="aPosition"/>
<parameter name="aX"/>
<parameter name="aY"/>
<parameter name="aAttributesOverride"/>
<body>
<![CDATA[
this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
]]>
</body>
</method>
<method name="sizeTo">
<parameter name="aWidth"/>
<parameter name="aHeight"/>
<body>
<![CDATA[
this.popupBoxObject.sizeTo(aWidth, aHeight);
]]>
</body>
</method>
<method name="getOuterScreenRect">
<body>
<![CDATA[
return this.popupBoxObject.getOuterScreenRect();
]]>
</body>
</method>
<method name="setConstraintRect">
<parameter name="aRect"/>
<body>
<![CDATA[
this.popupBoxObject.setConstraintRect(aRect);
]]>
</body>
</method>
</implementation>
</binding>
<binding id="popup"
@ -343,30 +152,6 @@
</content>
<implementation>
<field name="_fadeTimer">null</field>
<method name="sizeTo">
<parameter name="aWidth"/>
<parameter name="aHeight"/>
<body>
<![CDATA[
this.popupBoxObject.sizeTo(aWidth, aHeight);
if (this.state == "open") {
this.adjustArrowPosition();
}
]]>
</body>
</method>
<method name="moveToAnchor">
<parameter name="aAnchorElement"/>
<parameter name="aPosition"/>
<parameter name="aX"/>
<parameter name="aY"/>
<parameter name="aAttributesOverride"/>
<body>
<![CDATA[
this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
]]>
</body>
</method>
<method name="adjustArrowPosition">
<body>
<![CDATA[

View File

@ -215,7 +215,7 @@ function PopupNotifications(tabbrowser, panel,
throw "Invalid tabbrowser";
if (iconBox && ChromeUtils.getClassName(iconBox) != "XULElement")
throw "Invalid iconBox";
if (ChromeUtils.getClassName(panel) != "XULElement")
if (ChromeUtils.getClassName(panel) != "XULPopupElement")
throw "Invalid panel";
this._shouldSuppress = options.shouldSuppress || (() => false);