Bug 801609 - Simplify popup and contextmenu handling and make the listener skippable, r=mccr8

--HG--
rename : content/canvas/test/test_toBlob.html => content/canvas/test/test_mozGetAsFile.html
rename : dom/base/test/test_gsp-qualified.html => dom/base/test/test_gsp-standards.html
extra : rebase_source : 8e017d2fa6ff12cfcf0b0f8a56dadd541aca16bf
This commit is contained in:
Olli Pettay 2012-10-16 15:37:26 +03:00
Родитель 1fa0cf26bb
Коммит 58213a9d14
6 изменённых файлов: 58 добавлений и 90 удалений

Просмотреть файл

@ -1165,9 +1165,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
tmp->DeleteProperty(nsGkAtoms::itemtype);
tmp->DeleteProperty(nsGkAtoms::itemref);
tmp->DeleteProperty(nsGkAtoms::itemprop);
} else if (tmp->IsXUL()) {
tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
tmp->DeleteProperty(nsGkAtoms::popuplistener);
}
}
@ -1708,13 +1705,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
cb.NoteXPCOMChild(property);
property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemtype));
cb.NoteXPCOMChild(property);
} else if (tmp->IsXUL()) {
nsISupports* property = static_cast<nsISupports*>
(tmp->GetProperty(nsGkAtoms::contextmenulistener));
cb.NoteXPCOMChild(property);
property = static_cast<nsISupports*>
(tmp->GetProperty(nsGkAtoms::popuplistener));
cb.NoteXPCOMChild(property);
}
}

Просмотреть файл

@ -226,7 +226,6 @@ GK_ATOM(headerContentStyleType, "content-style-type")
GK_ATOM(headerContentType, "content-type")
GK_ATOM(context, "context")
GK_ATOM(contextmenu, "contextmenu")
GK_ATOM(contextmenulistener, "contextmenulistener")
GK_ATOM(control, "control")
GK_ATOM(controls, "controls")
GK_ATOM(coords, "coords")
@ -833,7 +832,6 @@ GK_ATOM(popupanchor, "popupanchor")
GK_ATOM(popupgroup, "popupgroup")
GK_ATOM(popuphidden, "popuphidden")
GK_ATOM(popuphiding, "popuphiding")
GK_ATOM(popuplistener, "popuplistener")
GK_ATOM(popupset, "popupset")
GK_ATOM(popupshowing, "popupshowing")
GK_ATOM(popupshown, "popupshown")

Просмотреть файл

@ -1554,58 +1554,26 @@ nsXULElement::IsNodeOfType(uint32_t aFlags) const
return !(aFlags & ~eCONTENT);
}
static void
PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
void* aPropertyValue, void* aData)
{
nsIDOMEventListener* listener =
static_cast<nsIDOMEventListener*>(aPropertyValue);
if (!listener) {
return;
}
nsEventListenerManager* manager = static_cast<nsINode*>(aObject)->
GetListenerManager(false);
if (manager) {
manager->RemoveEventListenerByType(listener,
NS_LITERAL_STRING("mousedown"),
NS_EVENT_FLAG_BUBBLE |
NS_EVENT_FLAG_SYSTEM_EVENT);
manager->RemoveEventListenerByType(listener,
NS_LITERAL_STRING("contextmenu"),
NS_EVENT_FLAG_BUBBLE |
NS_EVENT_FLAG_SYSTEM_EVENT);
}
NS_RELEASE(listener);
}
nsresult
nsXULElement::AddPopupListener(nsIAtom* aName)
{
// Add a popup listener to the element
bool isContext = (aName == nsGkAtoms::context ||
aName == nsGkAtoms::contextmenu);
nsIAtom* listenerAtom = isContext ?
nsGkAtoms::contextmenulistener :
nsGkAtoms::popuplistener;
uint32_t listenerFlag = isContext ?
XUL_ELEMENT_HAS_CONTENTMENU_LISTENER :
XUL_ELEMENT_HAS_POPUP_LISTENER;
nsCOMPtr<nsIDOMEventListener> popupListener =
static_cast<nsIDOMEventListener*>(GetProperty(listenerAtom));
if (popupListener) {
// Popup listener is already installed.
if (HasFlag(listenerFlag)) {
return NS_OK;
}
popupListener = new nsXULPopupListener(this, isContext);
nsCOMPtr<nsIDOMEventListener> listener =
new nsXULPopupListener(this, isContext);
// Add the popup as a listener on this element.
nsEventListenerManager* manager = GetListenerManager(true);
NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
nsresult rv = SetProperty(listenerAtom, popupListener,
PopupListenerPropertyDtor, true);
NS_ENSURE_SUCCESS(rv, rv);
// Want the property to have a reference to the listener.
nsIDOMEventListener* listener = nullptr;
popupListener.swap(listener);
SetFlags(listenerFlag);
if (isContext) {
manager->AddEventListenerByType(listener,

Просмотреть файл

@ -321,11 +321,13 @@ public:
// XUL element specific bits
enum {
XUL_ELEMENT_TEMPLATE_GENERATED = XUL_ELEMENT_FLAG_BIT(0)
XUL_ELEMENT_TEMPLATE_GENERATED = XUL_ELEMENT_FLAG_BIT(0),
XUL_ELEMENT_HAS_CONTENTMENU_LISTENER = XUL_ELEMENT_FLAG_BIT(1),
XUL_ELEMENT_HAS_POPUP_LISTENER = XUL_ELEMENT_FLAG_BIT(2)
};
// Make sure we have space for our bit
PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET < 32);
// Make sure we have space for our bits
PR_STATIC_ASSERT((ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2) < 32);
#undef XUL_ELEMENT_FLAG_BIT

Просмотреть файл

@ -33,7 +33,7 @@
#include "nsHTMLReflowState.h"
#include "nsIObjectLoadingContent.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FragmentOrElement.h"
// for event firing in context menus
#include "nsPresContext.h"
@ -52,7 +52,8 @@ using namespace mozilla;
#define NS_CONTEXT_MENU_IS_MOUSEUP 1
#endif
nsXULPopupListener::nsXULPopupListener(nsIDOMElement *aElement, bool aIsContext)
nsXULPopupListener::nsXULPopupListener(mozilla::dom::Element* aElement,
bool aIsContext)
: mElement(aElement), mPopupContent(nullptr), mIsContext(aIsContext)
{
}
@ -66,6 +67,25 @@ NS_IMPL_CYCLE_COLLECTION_2(nsXULPopupListener, mElement, mPopupContent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPopupListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPopupListener)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXULPopupListener)
// If the owner, mElement, can be skipped, so can we.
if (tmp->mElement) {
return mozilla::dom::FragmentOrElement::CanSkip(tmp->mElement, true);
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXULPopupListener)
if (tmp->mElement) {
return mozilla::dom::FragmentOrElement::CanSkipInCC(tmp->mElement);
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXULPopupListener)
if (tmp->mElement) {
return mozilla::dom::FragmentOrElement::CanSkipThis(tmp->mElement);
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPopupListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsISupports)
@ -307,44 +327,37 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
{
nsresult rv = NS_OK;
nsAutoString type(NS_LITERAL_STRING("popup"));
if (mIsContext)
type.AssignLiteral("context");
nsIAtom* type = mIsContext ? nsGkAtoms::context : nsGkAtoms::popup;
nsAutoString identifier;
mElement->GetAttribute(type, identifier);
mElement->GetAttr(kNameSpaceID_None, type, identifier);
if (identifier.IsEmpty()) {
if (type.EqualsLiteral("popup"))
mElement->GetAttribute(NS_LITERAL_STRING("menu"), identifier);
else if (type.EqualsLiteral("context"))
mElement->GetAttribute(NS_LITERAL_STRING("contextmenu"), identifier);
if (type == nsGkAtoms::popup) {
mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::menu, identifier);
} else {
mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::contextmenu, identifier);
}
if (identifier.IsEmpty())
return rv;
}
// Try to find the popup content and the document.
nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
nsCOMPtr<nsIDocument> document = content->GetDocument();
// Turn the document into a DOM document so we can use getElementById
nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document);
if (!domDocument) {
NS_ERROR("Popup attached to an element that isn't in XUL!");
nsCOMPtr<nsIDocument> document = mElement->GetDocument();
if (!document) {
NS_WARNING("No document!");
return NS_ERROR_FAILURE;
}
// Handle the _child case for popups and context menus
nsCOMPtr<nsIDOMElement> popupElement;
nsCOMPtr<nsIContent> popup;
if (identifier.EqualsLiteral("_child")) {
nsCOMPtr<nsIContent> popup = GetImmediateChild(content, nsGkAtoms::menupopup);
if (popup)
popupElement = do_QueryInterface(popup);
else {
nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
popup = GetImmediateChild(mElement, nsGkAtoms::menupopup);
if (!popup) {
nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(document));
nsCOMPtr<nsIDOMNodeList> list;
nsDoc->GetAnonymousNodes(mElement, getter_AddRefs(list));
nsCOMPtr<nsIDOMElement> el = do_QueryInterface(mElement);
nsDoc->GetAnonymousNodes(el, getter_AddRefs(list));
if (list) {
uint32_t ctr,listLength;
nsCOMPtr<nsIDOMNode> node;
@ -355,15 +368,13 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
kNameSpaceID_XUL)) {
popupElement = do_QueryInterface(childContent);
popup.swap(childContent);
break;
}
}
}
}
}
else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
getter_AddRefs(popupElement)))) {
} else if (!(popup = document->GetElementById(identifier))) {
// Use getElementById to obtain the popup content and gracefully fail if
// we didn't find any popup content in the document.
NS_ERROR("GetElementById had some kind of spasm.");
@ -371,12 +382,11 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
}
// return if no popup was found or the popup is the element itself.
if ( !popupElement || popupElement == mElement)
if (!popup || popup == mElement)
return NS_OK;
// Submenus can't be used as context menus or popups, bug 288763.
// Similar code also in nsXULTooltipListener::GetTooltipFor.
nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
nsIContent* parent = popup->GetParent();
if (parent) {
nsMenuFrame* menu = do_QueryFrame(parent->GetPrimaryFrame());
@ -397,7 +407,7 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
(mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
(mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) &&
mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)))) {
pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0,
pm->ShowPopup(mPopupContent, mElement, EmptyString(), 0, 0,
false, true, false, aEvent);
}
else {

Просмотреть файл

@ -12,7 +12,7 @@
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
#include "nsIDOMElement.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMEventListener.h"
@ -25,12 +25,12 @@ public:
// false, the popup opens on left click on aElement or a descendant. If
// aIsContext is true, the popup is a context menu which opens on a
// context menu event.
nsXULPopupListener(nsIDOMElement *aElement, bool aIsContext);
nsXULPopupListener(mozilla::dom::Element* aElement, bool aIsContext);
virtual ~nsXULPopupListener(void);
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsXULPopupListener)
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(nsXULPopupListener)
NS_DECL_NSIDOMEVENTLISTENER
protected:
@ -48,7 +48,7 @@ private:
#endif
// |mElement| is the node to which this listener is attached.
nsCOMPtr<nsIDOMElement> mElement;
nsCOMPtr<mozilla::dom::Element> mElement;
// The popup that is getting shown on top of mElement.
nsCOMPtr<nsIContent> mPopupContent;