2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Chris Waterson <waterson@netscape.com>
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
|
|
* Peter Annema <disttsc@bart.nl>
|
|
|
|
* Brendan Eich <brendan@mozilla.org>
|
|
|
|
* Mike Shaver <shaver@mozilla.org>
|
|
|
|
* Mark Hammond <mhammond@skippinet.com.au>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This Original Code has been modified by IBM Corporation.
|
|
|
|
* Modifications made by IBM described herein are
|
|
|
|
* Copyright (c) International Business Machines
|
|
|
|
* Corporation, 2000
|
|
|
|
*
|
|
|
|
* Modifications to Mozilla code or documentation
|
|
|
|
* identified per MPL Section 3.3
|
|
|
|
*
|
|
|
|
* Date Modified by Description of modification
|
|
|
|
* 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
|
|
|
|
* use in OS2
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsDOMCID.h"
|
|
|
|
#include "nsDOMError.h"
|
|
|
|
#include "nsDOMString.h"
|
|
|
|
#include "nsIDOMEvent.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
#include "nsHashtable.h"
|
|
|
|
#include "nsIAtom.h"
|
2007-10-29 21:03:42 -07:00
|
|
|
#include "nsIBaseWindow.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMAttr.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMMouseListener.h"
|
|
|
|
#include "nsIDOMMouseMotionListener.h"
|
|
|
|
#include "nsIDOMLoadListener.h"
|
|
|
|
#include "nsIDOMFocusListener.h"
|
|
|
|
#include "nsIDOMKeyListener.h"
|
|
|
|
#include "nsIDOMFormListener.h"
|
|
|
|
#include "nsIDOMContextMenuListener.h"
|
|
|
|
#include "nsIDOMEventListener.h"
|
2007-05-14 02:11:38 -07:00
|
|
|
#include "nsIDOMEventTarget.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMXULCommandDispatcher.h"
|
|
|
|
#include "nsIDOMXULElement.h"
|
|
|
|
#include "nsIDOMElementCSSInlineStyle.h"
|
|
|
|
#include "nsIDOMXULSelectCntrlItemEl.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIEventListenerManager.h"
|
|
|
|
#include "nsIEventStateManager.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIFastLoadService.h"
|
|
|
|
#include "nsHTMLStyleSheet.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIObjectInputStream.h"
|
|
|
|
#include "nsIObjectOutputStream.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
#include "nsIRDFCompositeDataSource.h"
|
|
|
|
#include "nsIRDFNode.h"
|
|
|
|
#include "nsIRDFService.h"
|
|
|
|
#include "nsIScriptContext.h"
|
|
|
|
#include "nsIScriptRuntime.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIScriptGlobalObjectOwner.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsICSSStyleRule.h"
|
|
|
|
#include "nsIStyleSheet.h"
|
2009-04-08 13:52:37 -07:00
|
|
|
#include "nsDOMCSSAttrDeclaration.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsIViewManager.h"
|
|
|
|
#include "nsIWidget.h"
|
|
|
|
#include "nsIXULDocument.h"
|
|
|
|
#include "nsIXULTemplateBuilder.h"
|
|
|
|
#include "nsIXBLService.h"
|
|
|
|
#include "nsLayoutCID.h"
|
|
|
|
#include "nsContentCID.h"
|
|
|
|
#include "nsRDFCID.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsXULControllers.h"
|
|
|
|
#include "nsIBoxObject.h"
|
|
|
|
#include "nsPIBoxObject.h"
|
|
|
|
#include "nsXULDocument.h"
|
2007-07-04 08:49:38 -07:00
|
|
|
#include "nsXULPopupListener.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsRuleWalker.h"
|
|
|
|
#include "nsIDOMViewCSS.h"
|
|
|
|
#include "nsIDOMCSSStyleDeclaration.h"
|
|
|
|
#include "nsCSSDeclaration.h"
|
|
|
|
#include "nsIListBoxObject.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsContentList.h"
|
|
|
|
#include "nsMutationEvent.h"
|
|
|
|
#include "nsIDOMMutationEvent.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsDOMAttributeMap.h"
|
|
|
|
#include "nsDOMCSSDeclaration.h"
|
2007-08-06 08:27:19 -07:00
|
|
|
#include "nsStyledElement.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsXULContentUtils.h"
|
|
|
|
#include "nsNodeUtils.h"
|
2008-03-21 04:18:10 -07:00
|
|
|
#include "nsFrameLoader.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "prlog.h"
|
|
|
|
#include "rdf.h"
|
2009-06-23 03:07:39 -07:00
|
|
|
#include "nsIDOM3EventTarget.h"
|
|
|
|
#include "nsIDOMEventGroup.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIControllers.h"
|
|
|
|
|
|
|
|
// The XUL doc interface
|
|
|
|
#include "nsIDOMXULDocument.h"
|
|
|
|
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsITimelineService.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsNodeInfoManager.h"
|
|
|
|
#include "nsXBLBinding.h"
|
|
|
|
#include "nsEventDispatcher.h"
|
2007-05-22 14:45:03 -07:00
|
|
|
#include "nsPresShellIterator.h"
|
2008-04-11 10:29:06 -07:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2008-06-04 13:23:37 -07:00
|
|
|
#include "nsIDOMXULCommandEvent.h"
|
|
|
|
#include "nsIDOMNSEvent.h"
|
2008-10-08 04:41:52 -07:00
|
|
|
#include "nsCCUncollectableMarker.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Global object maintenance
|
|
|
|
nsICSSParser* nsXULPrototypeElement::sCSSParser = nsnull;
|
|
|
|
nsIXBLService * nsXULElement::gXBLService = nsnull;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A tearoff class for nsXULElement to implement nsIScriptEventHandlerOwner.
|
|
|
|
*/
|
|
|
|
class nsScriptEventHandlerOwnerTearoff : public nsIScriptEventHandlerOwner
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsScriptEventHandlerOwnerTearoff(nsXULElement* aElement)
|
|
|
|
: mElement(aElement) {}
|
|
|
|
|
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptEventHandlerOwnerTearoff)
|
|
|
|
|
|
|
|
// nsIScriptEventHandlerOwner
|
|
|
|
virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
|
|
|
|
nsISupports* aTarget,
|
|
|
|
nsIAtom *aName,
|
|
|
|
const nsAString& aBody,
|
|
|
|
const char* aURL,
|
|
|
|
PRUint32 aLineNo,
|
|
|
|
nsScriptObjectHolder &aHandler);
|
|
|
|
virtual nsresult GetCompiledEventHandler(nsIAtom *aName,
|
|
|
|
nsScriptObjectHolder &aHandler);
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsRefPtr<nsXULElement> mElement;
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID);
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
#ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumElements;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumAttributes;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumEventHandlers;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumCacheTests;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumCacheHits;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumCacheSets;
|
|
|
|
PRUint32 nsXULPrototypeAttribute::gNumCacheFills;
|
|
|
|
#endif
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
class nsXULElementTearoff : public nsIDOMElementCSSInlineStyle,
|
|
|
|
public nsIFrameLoaderOwner
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
public:
|
2008-03-21 04:18:10 -07:00
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULElementTearoff,
|
|
|
|
nsIDOMElementCSSInlineStyle)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsXULElementTearoff(nsXULElement *aElement)
|
|
|
|
: mElement(aElement)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
NS_FORWARD_NSIDOMELEMENTCSSINLINESTYLE(static_cast<nsXULElement*>(mElement.get())->)
|
|
|
|
NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->);
|
2007-03-22 10:30:00 -07:00
|
|
|
private:
|
2008-03-21 04:18:10 -07:00
|
|
|
nsCOMPtr<nsIDOMXULElement> mElement;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_1(nsXULElementTearoff, mElement)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULElementTearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULElementTearoff)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULElementTearoff)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIFrameLoaderOwner)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
|
|
|
|
NS_INTERFACE_MAP_END_AGGREGATED(mElement)
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsXULElement
|
|
|
|
//
|
|
|
|
|
|
|
|
nsXULElement::nsXULElement(nsINodeInfo* aNodeInfo)
|
|
|
|
: nsGenericElement(aNodeInfo),
|
|
|
|
mBindingParent(nsnull)
|
|
|
|
{
|
|
|
|
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXULElement::nsXULSlots::nsXULSlots(PtrBits aFlags)
|
|
|
|
: nsXULElement::nsDOMSlots(aFlags)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXULElement::nsXULSlots::~nsXULSlots()
|
|
|
|
{
|
|
|
|
NS_IF_RELEASE(mControllers); // Forces release
|
2008-03-21 04:18:10 -07:00
|
|
|
if (mFrameLoader) {
|
|
|
|
mFrameLoader->Destroy();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsINode::nsSlots*
|
|
|
|
nsXULElement::CreateSlots()
|
|
|
|
{
|
2008-02-02 15:41:24 -08:00
|
|
|
return new nsXULSlots(mFlagsOrSlots);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
already_AddRefed<nsXULElement>
|
|
|
|
nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
|
|
|
|
PRBool aIsScriptable)
|
|
|
|
{
|
2008-02-02 15:41:24 -08:00
|
|
|
nsXULElement *element = new nsXULElement(aNodeInfo);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (element) {
|
|
|
|
NS_ADDREF(element);
|
|
|
|
|
|
|
|
element->mPrototype = aPrototype;
|
2007-09-18 01:38:24 -07:00
|
|
|
if (aPrototype->mHasIdAttribute) {
|
|
|
|
element->SetFlags(NODE_MAY_HAVE_ID);
|
|
|
|
}
|
|
|
|
if (aPrototype->mHasClassAttribute) {
|
|
|
|
element->SetFlags(NODE_MAY_HAVE_CLASS);
|
|
|
|
}
|
|
|
|
if (aPrototype->mHasStyleAttribute) {
|
|
|
|
element->SetFlags(NODE_MAY_HAVE_STYLE);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(aPrototype->mScriptTypeID != nsIProgrammingLanguage::UNKNOWN,
|
|
|
|
"Need to know the language!");
|
|
|
|
element->SetScriptTypeID(aPrototype->mScriptTypeID);
|
|
|
|
|
|
|
|
if (aIsScriptable) {
|
|
|
|
// Check each attribute on the prototype to see if we need to do
|
|
|
|
// any additional processing and hookup that would otherwise be
|
|
|
|
// done 'automagically' by SetAttr().
|
|
|
|
for (PRUint32 i = 0; i < aPrototype->mNumAttributes; ++i) {
|
|
|
|
element->AddListenerFor(aPrototype->mAttributes[i].mName,
|
|
|
|
PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::Create(nsXULPrototypeElement* aPrototype,
|
|
|
|
nsIDocument* aDocument,
|
|
|
|
PRBool aIsScriptable,
|
|
|
|
nsIContent** aResult)
|
|
|
|
{
|
|
|
|
// Create an nsXULElement from a prototype
|
|
|
|
NS_PRECONDITION(aPrototype != nsnull, "null ptr");
|
|
|
|
if (! aPrototype)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
|
|
|
if (aDocument) {
|
|
|
|
nsINodeInfo* ni = aPrototype->mNodeInfo;
|
2008-09-12 15:32:18 -07:00
|
|
|
nodeInfo = aDocument->NodeInfoManager()->GetNodeInfo(ni->NameAtom(),
|
|
|
|
ni->GetPrefixAtom(),
|
|
|
|
ni->NamespaceID());
|
2008-09-25 15:46:52 -07:00
|
|
|
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
nodeInfo = aPrototype->mNodeInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<nsXULElement> element = Create(aPrototype, nodeInfo,
|
|
|
|
aIsScriptable);
|
|
|
|
if (!element) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aResult = element.get());
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
NS_NewXULElement(nsIContent** aResult, nsINodeInfo *aNodeInfo)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNodeInfo, "need nodeinfo for non-proto Create");
|
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
// Create an nsXULElement with the specified namespace and tag.
|
2008-02-02 15:41:24 -08:00
|
|
|
nsXULElement* element = new nsXULElement(aNodeInfo);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(*aResult = element);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsISupports interface
|
|
|
|
|
2007-05-24 07:10:02 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
|
|
|
|
nsGenericElement)
|
2008-10-08 04:41:52 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPrototype,
|
|
|
|
nsXULPrototypeElement)
|
2007-05-24 07:10:02 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_ADDREF_INHERITED(nsXULElement, nsGenericElement)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsXULElement, nsGenericElement)
|
|
|
|
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULElement)
|
|
|
|
NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsXULElement)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMNode)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMElement)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMXULElement)
|
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_END
|
|
|
|
NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
|
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIScriptEventHandlerOwner,
|
|
|
|
new nsScriptEventHandlerOwnerTearoff(this))
|
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMElementCSSInlineStyle,
|
|
|
|
new nsXULElementTearoff(this))
|
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFrameLoaderOwner,
|
|
|
|
new nsXULElementTearoff(this))
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XULElement)
|
|
|
|
NS_ELEMENT_INTERFACE_MAP_END
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIDOMNode interface
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
// If we have a prototype, so will our clone.
|
|
|
|
nsRefPtr<nsXULElement> element;
|
|
|
|
if (mPrototype) {
|
|
|
|
element = nsXULElement::Create(mPrototype, aNodeInfo, PR_TRUE);
|
|
|
|
NS_ASSERTION(GetScriptTypeID() == mPrototype->mScriptTypeID,
|
|
|
|
"Didn't get the default language from proto?");
|
|
|
|
}
|
|
|
|
else {
|
2008-02-02 15:41:24 -08:00
|
|
|
element = new nsXULElement(aNodeInfo);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (element) {
|
|
|
|
// If created from a prototype, we will already have the script
|
|
|
|
// language specified by the proto - otherwise copy it directly
|
|
|
|
element->SetScriptTypeID(GetScriptTypeID());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!element) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX TODO: set up RDF generic builder n' stuff if there is a
|
|
|
|
// 'datasources' attribute? This is really kind of tricky,
|
|
|
|
// because then we'd need to -selectively- copy children that
|
|
|
|
// -weren't- generated from RDF. Ugh. Forget it.
|
|
|
|
|
|
|
|
// Note that we're _not_ copying mControllers.
|
|
|
|
|
|
|
|
nsresult rv = CopyInnerTo(element);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
NS_ADDREF(*aResult = element);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetElementsByAttribute(const nsAString& aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
|
|
|
|
NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
void* attrValue = new nsString(aValue);
|
|
|
|
NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsContentList *list =
|
|
|
|
new nsContentList(this,
|
|
|
|
nsXULDocument::MatchAttribute,
|
|
|
|
nsContentUtils::DestroyMatchString,
|
|
|
|
attrValue,
|
|
|
|
PR_TRUE,
|
|
|
|
attrAtom,
|
|
|
|
kNameSpaceID_Unknown);
|
|
|
|
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(*aReturn = list);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
|
|
|
|
NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
|
|
|
|
if (!aNamespaceURI.EqualsLiteral("*")) {
|
|
|
|
nsresult rv =
|
|
|
|
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
|
|
|
|
nameSpaceId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* attrValue = new nsString(aValue);
|
|
|
|
NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
nsContentList *list =
|
|
|
|
new nsContentList(this,
|
|
|
|
nsXULDocument::MatchAttribute,
|
|
|
|
nsContentUtils::DestroyMatchString,
|
|
|
|
attrValue,
|
|
|
|
PR_TRUE,
|
|
|
|
attrAtom,
|
|
|
|
nameSpaceId);
|
|
|
|
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(*aReturn = list);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::GetEventListenerManagerForAttr(nsIEventListenerManager** aManager,
|
|
|
|
nsISupports** aTarget,
|
|
|
|
PRBool* aDefer)
|
|
|
|
{
|
|
|
|
// XXXbz sXBL/XBL2 issue: should we instead use GetCurrentDoc()
|
|
|
|
// here, override BindToTree for those classes and munge event
|
|
|
|
// listeners there?
|
|
|
|
nsIDocument* doc = GetOwnerDoc();
|
|
|
|
if (!doc)
|
|
|
|
return NS_ERROR_UNEXPECTED; // XXX
|
|
|
|
|
2008-05-07 21:57:21 -07:00
|
|
|
nsPIDOMWindow *window;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIContent *root = doc->GetRootContent();
|
2008-05-07 21:57:21 -07:00
|
|
|
if ((!root || root == this) && !mNodeInfo->Equals(nsGkAtoms::overlay) &&
|
|
|
|
(window = doc->GetInnerWindow()) && window->IsInnerWindow()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(window);
|
|
|
|
if (!piTarget)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
*aDefer = PR_FALSE;
|
2009-06-23 04:23:52 -07:00
|
|
|
*aManager = piTarget->GetListenerManager(PR_TRUE);
|
|
|
|
NS_ENSURE_STATE(*aManager);
|
|
|
|
NS_ADDREF(*aManager);
|
|
|
|
NS_ADDREF(*aTarget = window);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericElement::GetEventListenerManagerForAttr(aManager,
|
|
|
|
aTarget,
|
|
|
|
aDefer);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::IsFocusable(PRInt32 *aTabIndex)
|
|
|
|
{
|
2008-03-07 08:33:38 -08:00
|
|
|
/*
|
|
|
|
* Returns true if an element may be focused, and false otherwise. The inout
|
|
|
|
* argument aTabIndex will be set to the tab order index to be used; -1 for
|
|
|
|
* elements that should not be part of the tab order and a greater value to
|
|
|
|
* indicate its tab order.
|
|
|
|
*
|
|
|
|
* Confusingly, the supplied value for the aTabIndex argument may indicate
|
|
|
|
* whether the element may be focused as a result of the -moz-user-focus
|
2008-03-27 09:19:05 -07:00
|
|
|
* property, where -1 means no and 0 means yes.
|
2008-03-07 08:33:38 -08:00
|
|
|
*
|
|
|
|
* For controls, the element cannot be focused and is not part of the tab
|
|
|
|
* order if it is disabled.
|
|
|
|
*
|
|
|
|
* Controls (those that implement nsIDOMXULControlElement):
|
|
|
|
* *aTabIndex = -1 no tabindex Not focusable or tabbable
|
|
|
|
* *aTabIndex = -1 tabindex="-1" Not focusable or tabbable
|
|
|
|
* *aTabIndex = -1 tabindex=">=0" Focusable and tabbable
|
|
|
|
* *aTabIndex >= 0 no tabindex Focusable and tabbable
|
|
|
|
* *aTabIndex >= 0 tabindex="-1" Focusable but not tabbable
|
|
|
|
* *aTabIndex >= 0 tabindex=">=0" Focusable and tabbable
|
|
|
|
* Non-controls:
|
|
|
|
* *aTabIndex = -1 Not focusable or tabbable
|
|
|
|
* *aTabIndex >= 0 Focusable and tabbable
|
|
|
|
*
|
|
|
|
* If aTabIndex is null, then the tabindex is not computed, and
|
|
|
|
* true is returned for non-disabled controls and false otherwise.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// elements are not focusable by default
|
|
|
|
PRBool shouldFocus = PR_FALSE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMXULControlElement> xulControl =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_QueryInterface(static_cast<nsIContent*>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (xulControl) {
|
2008-03-07 08:33:38 -08:00
|
|
|
// a disabled element cannot be focused and is not part of the tab order
|
|
|
|
PRBool disabled;
|
2007-03-22 10:30:00 -07:00
|
|
|
xulControl->GetDisabled(&disabled);
|
|
|
|
if (disabled) {
|
2008-03-07 08:33:38 -08:00
|
|
|
if (aTabIndex)
|
|
|
|
*aTabIndex = -1;
|
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-03-07 08:33:38 -08:00
|
|
|
shouldFocus = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aTabIndex) {
|
2008-03-27 09:19:05 -07:00
|
|
|
if (xulControl) {
|
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
|
|
|
|
// if either the aTabIndex argument or a specified tabindex is non-negative,
|
|
|
|
// the element becomes focusable.
|
|
|
|
PRInt32 tabIndex = 0;
|
|
|
|
xulControl->GetTabIndex(&tabIndex);
|
|
|
|
shouldFocus = *aTabIndex >= 0 || tabIndex >= 0;
|
|
|
|
*aTabIndex = tabIndex;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// otherwise, if there is no tabindex attribute, just use the value of
|
|
|
|
// *aTabIndex to indicate focusability
|
|
|
|
shouldFocus = *aTabIndex >= 0;
|
|
|
|
}
|
2008-03-13 07:07:23 -07:00
|
|
|
|
|
|
|
if (shouldFocus && sTabFocusModelAppliesToXUL &&
|
|
|
|
!(sTabFocusModel & eTabFocus_formElementsMask)) {
|
|
|
|
// By default, the tab focus model doesn't apply to xul element on any system but OS X.
|
|
|
|
// on OS X we're following it for UI elements (XUL) as sTabFocusModel is based on
|
|
|
|
// "Full Keyboard Access" system setting (see mac/nsILookAndFeel).
|
|
|
|
// both textboxes and list elements (i.e. trees and list) should always be focusable
|
|
|
|
// (textboxes are handled as html:input)
|
|
|
|
// For compatibility, we only do this for controls, otherwise elements like <browser>
|
|
|
|
// cannot take this focus.
|
|
|
|
if (!mNodeInfo->Equals(nsGkAtoms::tree) && !mNodeInfo->Equals(nsGkAtoms::listbox))
|
|
|
|
*aTabIndex = -1;
|
|
|
|
}
|
2008-03-07 08:33:38 -08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
shouldFocus = *aTabIndex >= 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-07 08:33:38 -08:00
|
|
|
return shouldFocus;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULElement::PerformAccesskey(PRBool aKeyCausesActivation,
|
|
|
|
PRBool aIsTrustedEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> content(this);
|
|
|
|
|
|
|
|
if (Tag() == nsGkAtoms::label) {
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
|
|
|
|
nsAutoString control;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::control, control);
|
|
|
|
if (!control.IsEmpty()) {
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDocument =
|
|
|
|
do_QueryInterface(content->GetCurrentDoc());
|
|
|
|
if (domDocument)
|
|
|
|
domDocument->GetElementById(control, getter_AddRefs(element));
|
|
|
|
}
|
|
|
|
// here we'll either change |content| to the element referenced by
|
|
|
|
// |element|, or clear it.
|
|
|
|
content = do_QueryInterface(element);
|
|
|
|
|
|
|
|
if (!content)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc)
|
|
|
|
return;
|
|
|
|
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = doc->GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!shell)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIFrame* frame = shell->GetPrimaryFrameFor(content);
|
|
|
|
if (!frame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const nsStyleVisibility* vis = frame->GetStyleVisibility();
|
|
|
|
|
|
|
|
if (vis->mVisible == NS_STYLE_VISIBILITY_COLLAPSE ||
|
|
|
|
vis->mVisible == NS_STYLE_VISIBILITY_HIDDEN ||
|
|
|
|
!frame->AreAncestorViewsVisible())
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULElement> elm(do_QueryInterface(content));
|
2007-11-11 14:44:48 -08:00
|
|
|
if (elm) {
|
|
|
|
// Define behavior for each type of XUL element.
|
|
|
|
nsIAtom *tag = content->Tag();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (tag != nsGkAtoms::toolbarbutton) {
|
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
2009-06-15 08:08:41 -07:00
|
|
|
if (fm) {
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
// for radio buttons, focus the radiogroup instead
|
|
|
|
if (tag == nsGkAtoms::radio) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> controlItem(do_QueryInterface(elm));
|
|
|
|
if (controlItem) {
|
|
|
|
PRBool disabled;
|
|
|
|
controlItem->GetDisabled(&disabled);
|
|
|
|
if (!disabled) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlElement> selectControl;
|
|
|
|
controlItem->GetControl(getter_AddRefs(selectControl));
|
|
|
|
element = do_QueryInterface(selectControl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
element = do_QueryInterface(content);
|
|
|
|
}
|
|
|
|
if (element)
|
|
|
|
fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
|
|
|
|
}
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
}
|
2007-11-28 12:14:12 -08:00
|
|
|
if (aKeyCausesActivation && tag != nsGkAtoms::textbox && tag != nsGkAtoms::menulist)
|
2007-11-11 14:44:48 -08:00
|
|
|
elm->Click();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
content->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIScriptEventHandlerOwner interface
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptEventHandlerOwnerTearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptEventHandlerOwnerTearoff)
|
|
|
|
tmp->mElement = nsnull;
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptEventHandlerOwnerTearoff)
|
2007-07-08 00:08:04 -07:00
|
|
|
cb.NoteXPCOMChild(static_cast<nsIContent*>(tmp->mElement));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2007-04-25 09:35:27 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptEventHandlerOwnerTearoff)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIScriptEventHandlerOwner)
|
|
|
|
NS_INTERFACE_MAP_END_AGGREGATED(mElement)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptEventHandlerOwnerTearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptEventHandlerOwnerTearoff)
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsScriptEventHandlerOwnerTearoff::GetCompiledEventHandler(
|
|
|
|
nsIAtom *aName,
|
|
|
|
nsScriptObjectHolder &aHandler)
|
|
|
|
{
|
|
|
|
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheTests);
|
|
|
|
aHandler.drop();
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute *attr =
|
|
|
|
mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
|
|
|
|
if (attr) {
|
|
|
|
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheHits);
|
|
|
|
aHandler.set(attr->mEventHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
|
|
|
|
nsIScriptContext* aContext,
|
|
|
|
nsISupports* aTarget,
|
|
|
|
nsIAtom *aName,
|
|
|
|
const nsAString& aBody,
|
|
|
|
const char* aURL,
|
|
|
|
PRUint32 aLineNo,
|
|
|
|
nsScriptObjectHolder &aHandler)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
|
|
|
|
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mElement->GetOwnerDoc());
|
|
|
|
|
|
|
|
nsIScriptContext *context;
|
2007-10-29 06:45:07 -07:00
|
|
|
nsXULPrototypeElement *elem = mElement->mPrototype;
|
|
|
|
if (elem && xuldoc) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// It'll be shared among the instances of the prototype.
|
|
|
|
|
|
|
|
// Use the prototype document's special context. Because
|
|
|
|
// scopeObject is null, the JS engine has no other source of
|
|
|
|
// <the-new-shared-event-handler>.__proto__ than to look in
|
|
|
|
// cx->globalObject for Function.prototype. That prototype
|
|
|
|
// keeps the global object alive, so if we use this document's
|
|
|
|
// global object, we'll be putting something in the prototype
|
|
|
|
// that protects this document's global object from GC.
|
|
|
|
nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner;
|
|
|
|
rv = xuldoc->GetScriptGlobalObjectOwner(getter_AddRefs(globalOwner));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ENSURE_TRUE(globalOwner, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsIScriptGlobalObject* global = globalOwner->GetScriptGlobalObject();
|
|
|
|
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
context = global->GetScriptContext(aContext->GetScriptTypeID());
|
|
|
|
// It could be possible the language has been setup on aContext but
|
|
|
|
// not on the global - we don't demand-create language contexts on the
|
|
|
|
// nsGlobalWindow
|
|
|
|
NS_ASSERTION(context,
|
|
|
|
"Failed to get a language context from the global!?");
|
|
|
|
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We don't have a prototype, so the passed context is ok.
|
|
|
|
NS_ASSERTION(aTarget != nsnull, "no prototype and no target?!");
|
|
|
|
context = aContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compile the event handler
|
|
|
|
PRUint32 argCount;
|
|
|
|
const char **argNames;
|
|
|
|
nsContentUtils::GetEventArgNames(kNameSpaceID_XUL, aName, &argCount,
|
|
|
|
&argNames);
|
2009-03-14 20:42:50 -07:00
|
|
|
|
|
|
|
nsCxPusher pusher;
|
|
|
|
if (!pusher.Push((JSContext*)context->GetNativeContext())) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = context->CompileEventHandler(aName, argCount, argNames,
|
2008-02-15 21:13:16 -08:00
|
|
|
aBody, aURL, aLineNo,
|
|
|
|
SCRIPTVERSION_DEFAULT, // for now?
|
|
|
|
aHandler);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// XXX: Shouldn't this use context and not aContext?
|
|
|
|
// XXXmarkh - is GetNativeGlobal() the correct scope?
|
|
|
|
rv = aContext->BindCompiledEventHandler(aTarget, aContext->GetNativeGlobal(),
|
|
|
|
aName, aHandler);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute *attr =
|
|
|
|
mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
|
|
|
|
if (attr) {
|
|
|
|
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
|
|
|
|
// take a copy of the event handler, and tell the language about it.
|
|
|
|
if (aHandler) {
|
2007-10-29 06:45:07 -07:00
|
|
|
NS_ASSERTION(!attr->mEventHandler, "Leaking handler.");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(),
|
2007-10-29 06:45:07 -07:00
|
|
|
elem,
|
|
|
|
&NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
|
|
|
|
aHandler,
|
|
|
|
elem->mHoldsScriptObject);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2007-10-29 06:45:07 -07:00
|
|
|
|
|
|
|
elem->mHoldsScriptObject = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
attr->mEventHandler = (void *)aHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULElement::AddListenerFor(const nsAttrName& aName,
|
|
|
|
PRBool aCompileEventHandlers)
|
|
|
|
{
|
|
|
|
// If appropriate, add a popup listener and/or compile the event
|
|
|
|
// handler. Called when we change the element's document, create a
|
|
|
|
// new element, change an attribute's value, etc.
|
|
|
|
// Eventlistenener-attributes are always in the null namespace
|
|
|
|
if (aName.IsAtom()) {
|
|
|
|
nsIAtom *attr = aName.Atom();
|
|
|
|
MaybeAddPopupListener(attr);
|
2007-04-02 10:17:36 -07:00
|
|
|
if (aCompileEventHandlers &&
|
|
|
|
nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAutoString value;
|
|
|
|
GetAttr(kNameSpaceID_None, attr, value);
|
|
|
|
AddScriptEventListener(attr, value, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName)
|
|
|
|
{
|
|
|
|
// If appropriate, add a popup listener. Called when we change the
|
|
|
|
// element's document, create a new element, change an attribute's
|
|
|
|
// value, etc.
|
|
|
|
if (aLocalName == nsGkAtoms::menu ||
|
|
|
|
aLocalName == nsGkAtoms::contextmenu ||
|
|
|
|
// XXXdwh popup and context are deprecated
|
|
|
|
aLocalName == nsGkAtoms::popup ||
|
|
|
|
aLocalName == nsGkAtoms::context) {
|
|
|
|
AddPopupListener(aLocalName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsIContent interface
|
|
|
|
//
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
nsresult
|
|
|
|
nsXULElement::BindToTree(nsIDocument* aDocument,
|
|
|
|
nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
|
|
|
PRBool aCompileEventHandlers)
|
|
|
|
{
|
|
|
|
nsresult rv = nsGenericElement::BindToTree(aDocument, aParent,
|
|
|
|
aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (aDocument) {
|
2009-01-02 07:41:43 -08:00
|
|
|
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
|
|
|
"Missing a script blocker!");
|
2008-03-21 04:18:10 -07:00
|
|
|
// We're in a document now. Kick off the frame load.
|
|
|
|
LoadSrc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-05-21 15:22:51 -07:00
|
|
|
void
|
|
|
|
nsXULElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|
|
|
{
|
|
|
|
// mControllers can own objects that are implemented
|
|
|
|
// in JavaScript (such as some implementations of
|
|
|
|
// nsIControllers. These objects prevent their global
|
|
|
|
// object's script object from being garbage collected,
|
|
|
|
// which means JS continues to hold an owning reference
|
|
|
|
// to the nsGlobalWindow, which owns the document,
|
|
|
|
// which owns this content. That's a cycle, so we break
|
|
|
|
// it here. (It might be better to break this by releasing
|
|
|
|
// mDocument in nsGlobalWindow::SetDocShell, but I'm not
|
|
|
|
// sure whether that would fix all possible cycles through
|
|
|
|
// mControllers.)
|
2008-03-21 04:18:10 -07:00
|
|
|
nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
|
2007-05-21 15:22:51 -07:00
|
|
|
if (slots) {
|
|
|
|
NS_IF_RELEASE(slots->mControllers);
|
2008-03-21 04:18:10 -07:00
|
|
|
if (slots->mFrameLoader) {
|
|
|
|
// This element is being taken out of the document, destroy the
|
|
|
|
// possible frame loader.
|
|
|
|
// XXXbz we really want to only partially destroy the frame
|
|
|
|
// loader... we don't want to tear down the docshell. Food for
|
|
|
|
// later bug.
|
|
|
|
slots->mFrameLoader->Destroy();
|
|
|
|
slots->mFrameLoader = nsnull;
|
|
|
|
}
|
2007-05-21 15:22:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsGenericElement::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2009-06-28 15:44:22 -07:00
|
|
|
nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify, PRBool aMutationEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-28 15:44:22 -07:00
|
|
|
NS_ASSERTION(aMutationEvent, "Someone tried to inhibit mutations on XUL child removal.");
|
2008-10-20 08:36:05 -07:00
|
|
|
nsresult rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
|
|
|
|
if (!oldKid) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
|
|
|
|
// the possibility exists that some of the items in the removed subtree
|
|
|
|
// are selected (and therefore need to be deselected). We need to account for this.
|
|
|
|
nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
|
|
|
|
nsCOMPtr<nsIListBoxObject> listBox;
|
|
|
|
PRBool fireSelectionHandler = PR_FALSE;
|
|
|
|
|
|
|
|
// -1 = do nothing, -2 = null out current item
|
|
|
|
// anything else = index to re-set as current
|
|
|
|
PRInt32 newCurrentIndex = -1;
|
|
|
|
|
|
|
|
if (oldKid->NodeInfo()->Equals(nsGkAtoms::listitem, kNameSpaceID_XUL)) {
|
|
|
|
// This is the nasty case. We have (potentially) a slew of selected items
|
|
|
|
// and cells going away.
|
|
|
|
// First, retrieve the tree.
|
|
|
|
// Check first whether this element IS the tree
|
2007-07-08 00:08:04 -07:00
|
|
|
controlElement = do_QueryInterface(static_cast<nsIContent*>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// If it's not, look at our parent
|
|
|
|
if (!controlElement)
|
|
|
|
rv = GetParentTree(getter_AddRefs(controlElement));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(oldKid);
|
|
|
|
if (controlElement && oldKidElem) {
|
|
|
|
// Iterate over all of the items and find out if they are contained inside
|
|
|
|
// the removed subtree.
|
|
|
|
PRInt32 length;
|
|
|
|
controlElement->GetSelectedCount(&length);
|
|
|
|
for (PRInt32 i = 0; i < length; i++) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> node;
|
|
|
|
controlElement->GetSelectedItem(i, getter_AddRefs(node));
|
|
|
|
// we need to QI here to do an XPCOM-correct pointercompare
|
|
|
|
nsCOMPtr<nsIDOMElement> selElem = do_QueryInterface(node);
|
|
|
|
if (selElem == oldKidElem &&
|
|
|
|
NS_SUCCEEDED(controlElement->RemoveItemFromSelection(node))) {
|
|
|
|
length--;
|
|
|
|
i--;
|
|
|
|
fireSelectionHandler = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
|
|
|
|
controlElement->GetCurrentItem(getter_AddRefs(curItem));
|
|
|
|
nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
|
|
|
|
if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, oldKid)) {
|
|
|
|
// Current item going away
|
|
|
|
nsCOMPtr<nsIBoxObject> box;
|
|
|
|
controlElement->GetBoxObject(getter_AddRefs(box));
|
|
|
|
listBox = do_QueryInterface(box);
|
|
|
|
if (listBox && oldKidElem) {
|
|
|
|
listBox->GetIndexOfItem(oldKidElem, &newCurrentIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If any of this fails, we'll just set the current item to null
|
|
|
|
if (newCurrentIndex == -1)
|
|
|
|
newCurrentIndex = -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-28 15:44:22 -07:00
|
|
|
rv = nsGenericElement::RemoveChildAt(aIndex, aNotify, aMutationEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (newCurrentIndex == -2)
|
|
|
|
controlElement->SetCurrentItem(nsnull);
|
|
|
|
else if (newCurrentIndex > -1) {
|
|
|
|
// Make sure the index is still valid
|
|
|
|
PRInt32 treeRows;
|
|
|
|
listBox->GetRowCount(&treeRows);
|
|
|
|
if (treeRows > 0) {
|
|
|
|
newCurrentIndex = PR_MIN((treeRows - 1), newCurrentIndex);
|
|
|
|
nsCOMPtr<nsIDOMElement> newCurrentItem;
|
|
|
|
listBox->GetItemAtIndex(newCurrentIndex, getter_AddRefs(newCurrentItem));
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> xulCurItem = do_QueryInterface(newCurrentItem);
|
|
|
|
if (xulCurItem)
|
|
|
|
controlElement->SetCurrentItem(xulCurItem);
|
|
|
|
} else {
|
|
|
|
controlElement->SetCurrentItem(nsnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument* doc;
|
|
|
|
if (fireSelectionHandler && (doc = GetCurrentDoc())) {
|
|
|
|
nsContentUtils::DispatchTrustedEvent(doc,
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsIContent*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_LITERAL_STRING("select"),
|
|
|
|
PR_FALSE,
|
|
|
|
PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
|
|
|
|
{
|
|
|
|
// If someone changes the accesskey, unregister the old one
|
|
|
|
//
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (doc && !aOldValue.IsEmpty()) {
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = doc->GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (shell) {
|
|
|
|
nsIContent *content = this;
|
|
|
|
|
|
|
|
// find out what type of content node this is
|
|
|
|
if (mNodeInfo->Equals(nsGkAtoms::label)) {
|
|
|
|
// For anonymous labels the unregistering must
|
|
|
|
// occur on the binding parent control.
|
2008-07-22 21:50:20 -07:00
|
|
|
// XXXldb: And what if the binding parent is null?
|
2007-03-22 10:30:00 -07:00
|
|
|
content = GetBindingParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content) {
|
|
|
|
shell->GetPresContext()->EventStateManager()->
|
|
|
|
UnregisterAccessKey(content, aOldValue.First());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|
|
|
const nsAString* aValue, PRBool aNotify)
|
|
|
|
{
|
|
|
|
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::accesskey &&
|
|
|
|
IsInDoc()) {
|
|
|
|
const nsAttrValue* attrVal = FindLocalOrProtoAttr(aNamespaceID, aName);
|
|
|
|
if (attrVal) {
|
|
|
|
nsAutoString oldValue;
|
|
|
|
attrVal->ToString(oldValue);
|
|
|
|
UnregisterAccessKey(oldValue);
|
|
|
|
}
|
2008-01-29 07:12:34 -08:00
|
|
|
}
|
|
|
|
else if (aNamespaceID == kNameSpaceID_None && (aName ==
|
|
|
|
nsGkAtoms::command || aName == nsGkAtoms::observes) && IsInDoc()) {
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
|
|
|
nsAutoString oldValue;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::observes, oldValue);
|
|
|
|
if (oldValue.IsEmpty()) {
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::command, oldValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!oldValue.IsEmpty()) {
|
|
|
|
RemoveBroadcaster(oldValue);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericElement::BeforeSetAttr(aNamespaceID, aName,
|
|
|
|
aValue, aNotify);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|
|
|
const nsAString* aValue, PRBool aNotify)
|
|
|
|
{
|
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
// XXX UnsetAttr handles more attributes then we do. See bug 233642.
|
|
|
|
|
|
|
|
// Add popup and event listeners. We can't call AddListenerFor since
|
|
|
|
// the attribute isn't set yet.
|
|
|
|
MaybeAddPopupListener(aName);
|
2007-04-02 10:17:36 -07:00
|
|
|
if (nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL) && aValue) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// If mPrototype->mScriptTypeID != GetScriptTypeID(), it means
|
|
|
|
// we are resolving an overlay with a different default script
|
|
|
|
// language. We can't defer compilation of those handlers as
|
|
|
|
// we will have lost the script language (storing it on each
|
|
|
|
// nsXULPrototypeAttribute is expensive!)
|
|
|
|
PRBool defer = mPrototype == nsnull ||
|
|
|
|
mPrototype->mScriptTypeID == GetScriptTypeID();
|
|
|
|
AddScriptEventListener(aName, *aValue, defer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hide chrome if needed
|
|
|
|
if (aName == nsGkAtoms::hidechrome &&
|
2007-12-04 08:50:32 -08:00
|
|
|
mNodeInfo->Equals(nsGkAtoms::window) &&
|
|
|
|
aValue) {
|
2007-03-22 10:30:00 -07:00
|
|
|
HideWindowChrome(aValue && NS_LITERAL_STRING("true").Equals(*aValue));
|
|
|
|
}
|
2008-08-17 19:10:28 -07:00
|
|
|
|
|
|
|
nsIDocument *document = GetCurrentDoc();
|
|
|
|
if (aName == nsGkAtoms::title &&
|
|
|
|
document && document->GetRootContent() == this) {
|
|
|
|
document->NotifyPossibleTitleChange(PR_FALSE);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-05-02 04:32:50 -07:00
|
|
|
// (in)activetitlebarcolor is settable on any root node (windows, dialogs, etc)
|
|
|
|
if ((aName == nsGkAtoms::activetitlebarcolor ||
|
|
|
|
aName == nsGkAtoms::inactivetitlebarcolor) &&
|
2007-10-29 21:03:42 -07:00
|
|
|
document && document->GetRootContent() == this) {
|
|
|
|
|
|
|
|
nscolor color = NS_RGBA(0, 0, 0, 0);
|
|
|
|
nsAttrValue attrValue;
|
|
|
|
attrValue.ParseColor(*aValue, document);
|
|
|
|
attrValue.GetColorValue(color);
|
|
|
|
|
2008-05-02 04:32:50 -07:00
|
|
|
SetTitlebarColor(color, aName == nsGkAtoms::activetitlebarcolor);
|
2007-10-29 21:03:42 -07:00
|
|
|
}
|
|
|
|
|
2009-07-29 11:33:53 -07:00
|
|
|
// if the localedir changed on the root element, reset the document direction
|
|
|
|
if (aName == nsGkAtoms::localedir &&
|
|
|
|
document && document->GetRootContent() == this) {
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
|
|
|
|
if (xuldoc) {
|
|
|
|
xuldoc->ResetDocumentDirection();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
if (aName == nsGkAtoms::src && document) {
|
|
|
|
LoadSrc();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXX need to check if they're changing an event handler: if
|
|
|
|
// so, then we need to unhook the old one. Or something.
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericElement::AfterSetAttr(aNamespaceID, aName,
|
|
|
|
aValue, aNotify);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::ParseAttribute(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
|
|
|
{
|
|
|
|
// Parse into a nsAttrValue
|
|
|
|
|
|
|
|
// WARNING!!
|
|
|
|
// This code is largely duplicated in nsXULPrototypeElement::SetAttrAt.
|
|
|
|
// Any changes should be made to both functions.
|
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
if (aAttribute == nsGkAtoms::style) {
|
2007-09-18 01:38:24 -07:00
|
|
|
SetFlags(NODE_MAY_HAVE_STYLE);
|
2008-02-19 09:52:00 -08:00
|
|
|
nsStyledElement::ParseStyleAttribute(this, aValue, aResult, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aAttribute == nsGkAtoms::_class) {
|
2007-09-18 01:38:24 -07:00
|
|
|
SetFlags(NODE_MAY_HAVE_CLASS);
|
2007-03-22 10:30:00 -07:00
|
|
|
aResult.ParseAtomArray(aValue);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nsGenericElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
|
|
|
aResult)) {
|
|
|
|
// Fall back to parsing as atom for short values
|
|
|
|
aResult.ParseStringOrAtom(aValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsAttrName*
|
|
|
|
nsXULElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
|
|
|
|
{
|
|
|
|
NS_ConvertUTF16toUTF8 name(aStr);
|
|
|
|
const nsAttrName* attrName =
|
|
|
|
mAttrsAndChildren.GetExistingAttrNameFromQName(name);
|
|
|
|
if (attrName) {
|
|
|
|
return attrName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mPrototype) {
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < mPrototype->mNumAttributes; ++i) {
|
|
|
|
attrName = &mPrototype->mAttributes[i].mName;
|
|
|
|
if (attrName->QualifiedNameEquals(name)) {
|
|
|
|
return attrName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
|
|
|
nsAString& aResult) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != aName, "must have attribute name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
|
|
|
|
"must have a real namespace ID!");
|
|
|
|
|
|
|
|
const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
|
|
|
|
|
|
|
|
if (!val) {
|
|
|
|
// Since we are returning a success code we'd better do
|
|
|
|
// something about the out parameters (someone may have
|
|
|
|
// given us a non-empty string).
|
|
|
|
aResult.Truncate();
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
val->ToString(aResult);
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != aName, "must have attribute name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
|
|
|
|
"must have a real namespace ID!");
|
|
|
|
|
|
|
|
return mAttrsAndChildren.GetAttr(aName, aNameSpaceID) ||
|
|
|
|
FindPrototypeAttribute(aNameSpaceID, aName);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::AttrValueIs(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aName,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsCaseTreatment aCaseSensitive) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aName, "Must have attr name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
|
|
|
|
|
|
|
|
const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
|
|
|
|
return val && val->Equals(aValue, aCaseSensitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::AttrValueIs(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aName,
|
|
|
|
nsIAtom* aValue,
|
|
|
|
nsCaseTreatment aCaseSensitive) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aName, "Must have attr name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
|
|
|
|
NS_ASSERTION(aValue, "Null value atom");
|
|
|
|
|
|
|
|
const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
|
|
|
|
return val && val->Equals(aValue, aCaseSensitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsXULElement::FindAttrValueIn(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aName,
|
|
|
|
AttrValuesArray* aValues,
|
|
|
|
nsCaseTreatment aCaseSensitive) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aName, "Must have attr name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
|
|
|
|
NS_ASSERTION(aValues, "Null value array");
|
|
|
|
|
|
|
|
const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
|
|
|
|
if (val) {
|
|
|
|
for (PRInt32 i = 0; aValues[i]; ++i) {
|
|
|
|
if (val->Equals(*aValues[i], aCaseSensitive)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ATTR_VALUE_NO_MATCH;
|
|
|
|
}
|
|
|
|
return ATTR_MISSING;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
|
|
|
|
{
|
2007-12-04 08:50:32 -08:00
|
|
|
// This doesn't call BeforeSetAttr/AfterSetAttr for now.
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(nsnull != aName, "must have attribute name");
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Because It's Hard to maintain a magic ``unset'' value in
|
|
|
|
// the local attributes, we'll fault all the attributes,
|
|
|
|
// unhook ourselves from the prototype, and then remove the
|
|
|
|
// local copy of the attribute that we want to unset. In
|
|
|
|
// other words, we'll become ``heavyweight''.
|
|
|
|
//
|
|
|
|
// We can avoid this if the attribute isn't in the prototype,
|
|
|
|
// then we just need to remove it locally
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute *protoattr =
|
|
|
|
FindPrototypeAttribute(aNameSpaceID, aName);
|
|
|
|
if (protoattr) {
|
|
|
|
// We've got an attribute on the prototype, so we need to
|
|
|
|
// fully fault and remove the local copy.
|
|
|
|
rv = MakeHeavyweight();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
|
|
|
|
if (index < 0) {
|
|
|
|
NS_ASSERTION(!protoattr, "we used to have a protoattr, we should now "
|
|
|
|
"have a normal one");
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString oldValue;
|
|
|
|
GetAttr(aNameSpaceID, aName, oldValue);
|
|
|
|
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
|
2007-07-12 13:05:45 -07:00
|
|
|
|
|
|
|
// When notifying, make sure to keep track of states whose value
|
|
|
|
// depends solely on the value of an attribute.
|
|
|
|
PRUint32 stateMask;
|
|
|
|
if (aNotify) {
|
|
|
|
stateMask = PRUint32(IntrinsicState());
|
2009-06-29 11:36:25 -07:00
|
|
|
|
|
|
|
nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
|
|
|
|
nsIDOMMutationEvent::REMOVAL);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool hasMutationListeners = aNotify &&
|
|
|
|
nsContentUtils::HasMutationListeners(this,
|
2007-07-04 13:39:10 -07:00
|
|
|
NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMAttr> attrNode;
|
|
|
|
if (hasMutationListeners) {
|
|
|
|
nsAutoString attrName;
|
|
|
|
aName->ToString(attrName);
|
|
|
|
nsAutoString ns;
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
|
|
|
|
GetAttributeNodeNS(ns, attrName, getter_AddRefs(attrNode));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDOMSlots *slots = GetExistingDOMSlots();
|
|
|
|
if (slots && slots->mAttributeMap) {
|
|
|
|
slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue ignored;
|
|
|
|
rv = mAttrsAndChildren.RemoveAttrAt(index, ignored);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// XXX if the RemoveAttrAt() call fails, we might end up having removed
|
|
|
|
// the attribute from the attribute map even though the attribute is still
|
|
|
|
// on the element
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=296205
|
|
|
|
|
|
|
|
// Deal with modification of magical attributes that side-effect
|
|
|
|
// other things.
|
|
|
|
// XXX Know how to remove POPUP event listeners when an attribute is unset?
|
|
|
|
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aName == nsGkAtoms::hidechrome &&
|
|
|
|
mNodeInfo->Equals(nsGkAtoms::window)) {
|
|
|
|
HideWindowChrome(PR_FALSE);
|
|
|
|
}
|
|
|
|
|
2008-05-02 04:32:50 -07:00
|
|
|
if ((aName == nsGkAtoms::activetitlebarcolor ||
|
|
|
|
aName == nsGkAtoms::inactivetitlebarcolor) &&
|
2007-10-29 21:03:42 -07:00
|
|
|
doc && doc->GetRootContent() == this) {
|
|
|
|
// Use 0, 0, 0, 0 as the "none" color.
|
2008-05-02 04:32:50 -07:00
|
|
|
SetTitlebarColor(NS_RGBA(0, 0, 0, 0), aName == nsGkAtoms::activetitlebarcolor);
|
2007-10-29 21:03:42 -07:00
|
|
|
}
|
|
|
|
|
2009-07-29 11:33:53 -07:00
|
|
|
// if the localedir changed on the root element, reset the document direction
|
|
|
|
if (aName == nsGkAtoms::localedir &&
|
|
|
|
doc && doc->GetRootContent() == this) {
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
|
|
|
|
if (xuldoc) {
|
|
|
|
xuldoc->ResetDocumentDirection();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If the accesskey attribute is removed, unregister it here
|
2008-12-29 07:07:38 -08:00
|
|
|
// Also see nsXULLabelFrame, nsBoxFrame and nsTextBoxFrame's AttributeChanged
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aName == nsGkAtoms::accesskey || aName == nsGkAtoms::control) {
|
|
|
|
UnregisterAccessKey(oldValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if the OBSERVES attribute is being unset. If so, we
|
|
|
|
// need to remove our broadcaster goop completely.
|
|
|
|
if (doc && (aName == nsGkAtoms::observes ||
|
|
|
|
aName == nsGkAtoms::command)) {
|
2008-01-29 07:12:34 -08:00
|
|
|
RemoveBroadcaster(oldValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-10 18:14:55 -07:00
|
|
|
if (doc) {
|
2007-10-05 13:37:55 -07:00
|
|
|
nsRefPtr<nsXBLBinding> binding =
|
|
|
|
doc->BindingManager()->GetBinding(this);
|
2007-07-10 18:14:55 -07:00
|
|
|
if (binding)
|
|
|
|
binding->AttributeChanged(aName, aNameSpaceID, PR_TRUE, aNotify);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aNotify) {
|
2007-07-12 13:05:45 -07:00
|
|
|
stateMask = stateMask ^ PRUint32(IntrinsicState());
|
|
|
|
if (stateMask && doc) {
|
|
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, aNotify);
|
|
|
|
doc->ContentStatesChanged(this, nsnull, stateMask);
|
|
|
|
}
|
2007-07-10 18:14:55 -07:00
|
|
|
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
|
2007-07-12 13:05:45 -07:00
|
|
|
nsIDOMMutationEvent::REMOVAL,
|
|
|
|
stateMask);
|
2007-07-10 18:14:55 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (hasMutationListeners) {
|
2008-04-14 16:59:21 -07:00
|
|
|
mozAutoRemovableBlockerRemover blockerRemover;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
mutation.mRelatedNode = attrNode;
|
|
|
|
mutation.mAttrName = aName;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
if (!oldValue.IsEmpty())
|
|
|
|
mutation.mPrevAttrValue = do_GetAtom(oldValue);
|
|
|
|
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
|
2008-03-14 16:08:57 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
|
|
|
|
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
|
|
|
nsnull, &mutation);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-01-29 07:12:34 -08:00
|
|
|
void
|
|
|
|
nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(GetOwnerDoc());
|
|
|
|
if (xuldoc) {
|
|
|
|
nsCOMPtr<nsIDOMElement> broadcaster;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc (do_QueryInterface(xuldoc));
|
|
|
|
domDoc->GetElementById(broadcasterId, getter_AddRefs(broadcaster));
|
|
|
|
if (broadcaster) {
|
|
|
|
xuldoc->RemoveBroadcastListenerFor(broadcaster, this,
|
|
|
|
NS_LITERAL_STRING("*"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsAttrName*
|
|
|
|
nsXULElement::GetAttrNameAt(PRUint32 aIndex) const
|
|
|
|
{
|
|
|
|
PRUint32 localCount = mAttrsAndChildren.AttrCount();
|
|
|
|
PRUint32 protoCount = mPrototype ? mPrototype->mNumAttributes : 0;
|
|
|
|
|
|
|
|
if (localCount > protoCount) {
|
|
|
|
// More local than proto, put local first
|
|
|
|
|
|
|
|
// Is the index low enough to just grab a local attr?
|
|
|
|
if (aIndex < localCount) {
|
|
|
|
return mAttrsAndChildren.AttrNameAt(aIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
aIndex -= localCount;
|
|
|
|
|
|
|
|
// Search though prototype attributes while skipping names that exist in
|
|
|
|
// the local array.
|
|
|
|
for (PRUint32 i = 0; i < protoCount; i++) {
|
|
|
|
const nsAttrName* name = &mPrototype->mAttributes[i].mName;
|
|
|
|
if (mAttrsAndChildren.GetAttr(name->LocalName(), name->NamespaceID())) {
|
|
|
|
aIndex++;
|
|
|
|
}
|
|
|
|
if (i == aIndex) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// More proto than local, put proto first
|
|
|
|
|
|
|
|
// Is the index low enough to just grab a proto attr?
|
|
|
|
if (aIndex < protoCount) {
|
|
|
|
return &mPrototype->mAttributes[aIndex].mName;
|
|
|
|
}
|
|
|
|
|
|
|
|
aIndex -= protoCount;
|
|
|
|
|
|
|
|
// Search though local attributes while skipping names that exist in
|
|
|
|
// the prototype array.
|
|
|
|
for (PRUint32 i = 0; i < localCount; i++) {
|
|
|
|
const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
|
|
|
|
|
|
|
|
for (PRUint32 j = 0; j < protoCount; j++) {
|
|
|
|
if (mPrototype->mAttributes[j].mName.Equals(*name)) {
|
|
|
|
aIndex++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == aIndex) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsXULElement::GetAttrCount() const
|
|
|
|
{
|
|
|
|
PRUint32 localCount = mAttrsAndChildren.AttrCount();
|
|
|
|
PRUint32 protoCount = mPrototype ? mPrototype->mNumAttributes : 0;
|
|
|
|
|
|
|
|
if (localCount > protoCount) {
|
|
|
|
// More local than proto, remove dups from proto array
|
|
|
|
PRUint32 count = localCount;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < protoCount; i++) {
|
|
|
|
const nsAttrName* name = &mPrototype->mAttributes[i].mName;
|
|
|
|
if (!mAttrsAndChildren.GetAttr(name->LocalName(), name->NamespaceID())) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// More proto than local, remove dups from local array
|
|
|
|
PRUint32 count = protoCount;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < localCount; i++) {
|
|
|
|
const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
for (PRUint32 j = 0; j < protoCount; j++) {
|
|
|
|
if (mPrototype->mAttributes[j].mName.Equals(*name)) {
|
|
|
|
count--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2007-11-30 09:57:03 -08:00
|
|
|
void
|
|
|
|
nsXULElement::DestroyContent()
|
|
|
|
{
|
2008-03-21 04:18:10 -07:00
|
|
|
nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
|
2007-11-30 09:57:03 -08:00
|
|
|
if (slots) {
|
2008-03-21 04:18:10 -07:00
|
|
|
NS_IF_RELEASE(slots->mControllers);
|
|
|
|
if (slots->mFrameLoader) {
|
|
|
|
slots->mFrameLoader->Destroy();
|
|
|
|
slots->mFrameLoader = nsnull;
|
|
|
|
}
|
2007-11-30 09:57:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsGenericElement::DestroyContent();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
nsXULElement::List(FILE* out, PRInt32 aIndent) const
|
|
|
|
{
|
2009-08-13 08:38:23 -07:00
|
|
|
nsCString prefix("XUL");
|
2007-03-22 10:30:00 -07:00
|
|
|
if (HasSlots()) {
|
|
|
|
prefix.Append('*');
|
|
|
|
}
|
|
|
|
prefix.Append(' ');
|
|
|
|
|
|
|
|
nsGenericElement::List(out, aIndent, prefix);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
|
|
|
|
nsIAtom* tag = Tag();
|
2009-06-23 03:07:39 -07:00
|
|
|
if (IsRootOfNativeAnonymousSubtree() &&
|
|
|
|
(tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner) &&
|
|
|
|
(aVisitor.mEvent->message == NS_MOUSE_CLICK ||
|
|
|
|
aVisitor.mEvent->message == NS_MOUSE_DOUBLECLICK ||
|
|
|
|
aVisitor.mEvent->message == NS_XUL_COMMAND ||
|
2009-08-03 00:55:35 -07:00
|
|
|
aVisitor.mEvent->message == NS_CONTEXTMENU ||
|
|
|
|
aVisitor.mEvent->message == NS_DRAGDROP_START ||
|
|
|
|
aVisitor.mEvent->message == NS_DRAGDROP_GESTURE)) {
|
2009-06-23 03:07:39 -07:00
|
|
|
// Don't propagate these events from native anonymous scrollbar.
|
|
|
|
aVisitor.mCanHandle = PR_TRUE;
|
|
|
|
aVisitor.mParentTarget = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aVisitor.mEvent->message == NS_XUL_COMMAND &&
|
2009-06-30 00:56:40 -07:00
|
|
|
aVisitor.mEvent->eventStructType == NS_INPUT_EVENT &&
|
2007-07-08 00:08:04 -07:00
|
|
|
aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this) &&
|
2007-03-22 10:30:00 -07:00
|
|
|
tag != nsGkAtoms::command) {
|
2009-06-30 00:56:40 -07:00
|
|
|
// Check that we really have an xul command event. That will be handled
|
|
|
|
// in a special way.
|
|
|
|
nsCOMPtr<nsIDOMXULCommandEvent> xulEvent =
|
|
|
|
do_QueryInterface(aVisitor.mDOMEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
// See if we have a command elt. If so, we execute on the command
|
|
|
|
// instead of on our content element.
|
|
|
|
nsAutoString command;
|
2009-06-30 00:56:40 -07:00
|
|
|
if (xulEvent && GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
|
|
|
|
!command.IsEmpty()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Stop building the event target chain for the original event.
|
|
|
|
// We don't want it to propagate to any DOM nodes.
|
|
|
|
aVisitor.mCanHandle = PR_FALSE;
|
|
|
|
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetCurrentDoc()));
|
|
|
|
NS_ENSURE_STATE(domDoc);
|
|
|
|
nsCOMPtr<nsIDOMElement> commandElt;
|
|
|
|
domDoc->GetElementById(command, getter_AddRefs(commandElt));
|
|
|
|
nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
|
|
|
|
if (commandContent) {
|
|
|
|
// Create a new command event to dispatch to the element
|
|
|
|
// pointed to by the command attribute. The new event's
|
|
|
|
// sourceEvent will be the original command event that we're
|
|
|
|
// handling.
|
2008-06-04 13:23:37 -07:00
|
|
|
nsCOMPtr<nsIDOMNSEvent> nsevent =
|
|
|
|
do_QueryInterface(aVisitor.mDOMEvent);
|
|
|
|
while (nsevent) {
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> oTarget;
|
|
|
|
nsevent->GetOriginalTarget(getter_AddRefs(oTarget));
|
|
|
|
NS_ENSURE_STATE(!SameCOMIdentity(oTarget, commandContent));
|
|
|
|
nsCOMPtr<nsIDOMEvent> tmp;
|
|
|
|
nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
|
|
|
|
do_QueryInterface(nsevent);
|
|
|
|
if (commandEvent) {
|
|
|
|
commandEvent->GetSourceEvent(getter_AddRefs(tmp));
|
|
|
|
}
|
|
|
|
nsevent = do_QueryInterface(tmp);
|
|
|
|
}
|
|
|
|
|
2009-06-30 00:56:40 -07:00
|
|
|
nsInputEvent* orig =
|
|
|
|
static_cast<nsInputEvent*>(aVisitor.mEvent);
|
|
|
|
nsContentUtils::DispatchXULCommand(
|
|
|
|
commandContent,
|
|
|
|
NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
|
|
|
|
aVisitor.mDOMEvent,
|
|
|
|
nsnull,
|
|
|
|
orig->isControl,
|
|
|
|
orig->isAlt,
|
|
|
|
orig->isShift,
|
|
|
|
orig->isMeta);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
|
|
|
NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericElement::PreHandleEvent(aVisitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX This _should_ be an implementation method, _not_ publicly exposed :-(
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetResource(nsIRDFResource** aResource)
|
|
|
|
{
|
|
|
|
nsAutoString id;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::ref, id);
|
|
|
|
if (id.IsEmpty()) {
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!id.IsEmpty()) {
|
|
|
|
return nsXULContentUtils::RDFService()->
|
|
|
|
GetUnicodeResource(id, aResource);
|
|
|
|
}
|
|
|
|
*aResource = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetDatabase(nsIRDFCompositeDataSource** aDatabase)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIXULTemplateBuilder> builder;
|
|
|
|
GetBuilder(getter_AddRefs(builder));
|
|
|
|
|
|
|
|
if (builder)
|
|
|
|
builder->GetDatabase(aDatabase);
|
|
|
|
else
|
|
|
|
*aDatabase = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetBuilder(nsIXULTemplateBuilder** aBuilder)
|
|
|
|
{
|
|
|
|
*aBuilder = nsnull;
|
|
|
|
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(GetCurrentDoc());
|
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->GetTemplateBuilderFor(this, aBuilder);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation methods
|
|
|
|
|
|
|
|
/// XXX GetID must be defined here because we have proto attrs.
|
|
|
|
nsIAtom*
|
|
|
|
nsXULElement::GetID() const
|
|
|
|
{
|
2007-09-18 01:38:24 -07:00
|
|
|
if (!HasFlag(NODE_MAY_HAVE_ID)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2007-07-26 07:16:19 -07:00
|
|
|
const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(!attrVal ||
|
|
|
|
attrVal->Type() == nsAttrValue::eAtom ||
|
|
|
|
(attrVal->Type() == nsAttrValue::eString &&
|
|
|
|
attrVal->GetStringValue().IsEmpty()),
|
|
|
|
"unexpected attribute type");
|
|
|
|
|
|
|
|
if (attrVal && attrVal->Type() == nsAttrValue::eAtom) {
|
|
|
|
return attrVal->GetAtomValue();
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsAttrValue*
|
2008-09-10 20:22:20 -07:00
|
|
|
nsXULElement::DoGetClasses() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-10 20:22:20 -07:00
|
|
|
NS_ASSERTION(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
|
2007-03-22 10:30:00 -07:00
|
|
|
return FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsICSSStyleRule*
|
|
|
|
nsXULElement::GetInlineStyleRule()
|
|
|
|
{
|
2007-09-18 01:38:24 -07:00
|
|
|
if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
// Fetch the cached style rule from the attributes.
|
|
|
|
const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::style);
|
|
|
|
|
|
|
|
if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) {
|
|
|
|
return attrVal->GetCSSStyleRuleValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
|
|
|
|
{
|
2007-09-18 01:38:24 -07:00
|
|
|
SetFlags(NODE_MAY_HAVE_STYLE);
|
2007-03-22 10:30:00 -07:00
|
|
|
PRBool modification = PR_FALSE;
|
|
|
|
nsAutoString oldValueStr;
|
|
|
|
|
|
|
|
PRBool hasListeners = aNotify &&
|
|
|
|
nsContentUtils::HasMutationListeners(this,
|
2007-07-04 13:39:10 -07:00
|
|
|
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
|
|
|
this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// There's no point in comparing the stylerule pointers since we're always
|
|
|
|
// getting a new stylerule here. And we can't compare the stringvalues of
|
|
|
|
// the old and the new rules since both will point to the same declaration
|
|
|
|
// and thus will be the same.
|
|
|
|
if (hasListeners) {
|
|
|
|
// save the old attribute so we can set up the mutation event properly
|
|
|
|
// XXXbz if the old rule points to the same declaration as the new one,
|
|
|
|
// this is getting the new attr value, not the old one....
|
|
|
|
modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
|
|
|
|
oldValueStr);
|
|
|
|
}
|
|
|
|
else if (aNotify && IsInDoc()) {
|
|
|
|
modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue attrValue(aStyleRule);
|
|
|
|
|
|
|
|
return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nsnull, oldValueStr,
|
2008-12-03 02:39:21 -08:00
|
|
|
attrValue, modification, hasListeners, aNotify, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsChangeHint
|
|
|
|
nsXULElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType) const
|
|
|
|
{
|
|
|
|
nsChangeHint retval(NS_STYLE_HINT_NONE);
|
|
|
|
|
|
|
|
if (aAttribute == nsGkAtoms::value &&
|
|
|
|
(aModType == nsIDOMMutationEvent::REMOVAL ||
|
|
|
|
aModType == nsIDOMMutationEvent::ADDITION)) {
|
|
|
|
nsIAtom *tag = Tag();
|
|
|
|
if (tag == nsGkAtoms::label || tag == nsGkAtoms::description)
|
|
|
|
// Label and description dynamically morph between a normal
|
|
|
|
// block and a cropping single-line XUL text frame. If the
|
|
|
|
// value attribute is being added or removed, then we need to
|
|
|
|
// return a hint of frame change. (See bugzilla bug 95475 for
|
|
|
|
// details.)
|
|
|
|
retval = NS_STYLE_HINT_FRAMECHANGE;
|
|
|
|
} else {
|
|
|
|
// if left or top changes we reflow. This will happen in xul
|
2009-07-29 11:33:53 -07:00
|
|
|
// containers that manage positioned children such as a stack.
|
2007-03-22 10:30:00 -07:00
|
|
|
if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute)
|
|
|
|
retval = NS_STYLE_HINT_REFLOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(PRBool)
|
|
|
|
nsXULElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
|
|
|
{
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *
|
2007-07-26 07:16:19 -07:00
|
|
|
nsXULElement::GetIDAttributeName() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return nsGkAtoms::id;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *
|
|
|
|
nsXULElement::GetClassAttributeName() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::_class;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Controllers Methods
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetControllers(nsIControllers** aResult)
|
|
|
|
{
|
|
|
|
if (! Controllers()) {
|
|
|
|
nsDOMSlots* slots = GetDOMSlots();
|
|
|
|
if (!slots)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
rv = NS_NewXULControllers(nsnull, NS_GET_IID(nsIControllers),
|
2007-07-08 00:08:04 -07:00
|
|
|
reinterpret_cast<void**>(&slots->mControllers));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a controllers");
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aResult = Controllers();
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetBoxObject(nsIBoxObject** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
2009-03-29 17:44:48 -07:00
|
|
|
nsIDocument* nsDoc = GetOwnerDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return nsDoc ? nsDoc->GetBoxObjectFor(this, aResult) : NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Methods for setting/getting attributes from nsIDOMXULElement
|
|
|
|
#define NS_IMPL_XUL_STRING_ATTR(_method, _atom) \
|
|
|
|
NS_IMETHODIMP \
|
|
|
|
nsXULElement::Get##_method(nsAString& aReturn) \
|
|
|
|
{ \
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::_atom, aReturn); \
|
|
|
|
return NS_OK; \
|
|
|
|
} \
|
|
|
|
NS_IMETHODIMP \
|
|
|
|
nsXULElement::Set##_method(const nsAString& aValue) \
|
|
|
|
{ \
|
|
|
|
return SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, aValue, \
|
|
|
|
PR_TRUE); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NS_IMPL_XUL_BOOL_ATTR(_method, _atom) \
|
|
|
|
NS_IMETHODIMP \
|
|
|
|
nsXULElement::Get##_method(PRBool* aResult) \
|
|
|
|
{ \
|
|
|
|
*aResult = BoolAttrIsTrue(nsGkAtoms::_atom); \
|
|
|
|
\
|
|
|
|
return NS_OK; \
|
|
|
|
} \
|
|
|
|
NS_IMETHODIMP \
|
|
|
|
nsXULElement::Set##_method(PRBool aValue) \
|
|
|
|
{ \
|
|
|
|
if (aValue) \
|
|
|
|
SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, \
|
|
|
|
NS_LITERAL_STRING("true"), PR_TRUE); \
|
|
|
|
else \
|
|
|
|
UnsetAttr(kNameSpaceID_None, nsGkAtoms::_atom, PR_TRUE); \
|
|
|
|
\
|
|
|
|
return NS_OK; \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Id, id)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(ClassName, _class)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Align, align)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Dir, dir)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Flex, flex)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(FlexGroup, flexgroup)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Ordinal, ordinal)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Orient, orient)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Pack, pack)
|
|
|
|
NS_IMPL_XUL_BOOL_ATTR(Hidden, hidden)
|
|
|
|
NS_IMPL_XUL_BOOL_ATTR(Collapsed, collapsed)
|
|
|
|
NS_IMPL_XUL_BOOL_ATTR(AllowEvents, allowevents)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Observes, observes)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Menu, menu)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(ContextMenu, contextmenu)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Tooltip, tooltip)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Width, width)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Height, height)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(MinWidth, minwidth)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(MinHeight, minheight)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(MaxWidth, maxwidth)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(MaxHeight, maxheight)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Persist, persist)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Left, left)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Top, top)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Datasources, datasources)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(Ref, ref)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(TooltipText, tooltiptext)
|
|
|
|
NS_IMPL_XUL_STRING_ATTR(StatusText, statustext)
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
|
|
|
|
{
|
2007-04-29 10:58:52 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Clone the prototype rule, if we don't have a local one.
|
|
|
|
if (mPrototype &&
|
|
|
|
!mAttrsAndChildren.GetAttr(nsGkAtoms::style, kNameSpaceID_None)) {
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute *protoattr =
|
|
|
|
FindPrototypeAttribute(kNameSpaceID_None, nsGkAtoms::style);
|
|
|
|
if (protoattr && protoattr->mValue.Type() == nsAttrValue::eCSSStyleRule) {
|
|
|
|
nsCOMPtr<nsICSSRule> ruleClone;
|
|
|
|
rv = protoattr->mValue.GetCSSStyleRuleValue()->Clone(*getter_AddRefs(ruleClone));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAttrValue value;
|
|
|
|
nsCOMPtr<nsICSSStyleRule> styleRule = do_QueryInterface(ruleClone);
|
|
|
|
value.SetTo(styleRule);
|
|
|
|
|
|
|
|
rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, value);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsDOMSlots* slots = GetDOMSlots();
|
|
|
|
NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
if (!slots->mStyle) {
|
2009-09-02 17:28:37 -07:00
|
|
|
slots->mStyle = new nsDOMCSSAttributeDeclaration(this
|
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
, PR_FALSE
|
|
|
|
#endif // MOZ_SMIL
|
|
|
|
);
|
2009-04-08 13:52:37 -07:00
|
|
|
NS_ENSURE_TRUE(slots->mStyle, NS_ERROR_OUT_OF_MEMORY);
|
2007-09-18 01:38:24 -07:00
|
|
|
SetFlags(NODE_MAY_HAVE_STYLE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IF_ADDREF(*aStyle = slots->mStyle);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-03-21 04:18:10 -07:00
|
|
|
nsresult
|
|
|
|
nsXULElement::LoadSrc()
|
|
|
|
{
|
|
|
|
// Allow frame loader only on objects for which a container box object
|
|
|
|
// can be obtained.
|
|
|
|
nsIAtom* tag = Tag();
|
|
|
|
if (tag != nsGkAtoms::browser &&
|
|
|
|
tag != nsGkAtoms::editor &&
|
|
|
|
tag != nsGkAtoms::iframe) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (!IsInDoc() ||
|
|
|
|
!GetOwnerDoc()->GetRootContent() ||
|
|
|
|
GetOwnerDoc()->GetRootContent()->
|
|
|
|
NodeInfo()->Equals(nsGkAtoms::overlay, kNameSpaceID_XUL)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
nsXULSlots* slots = static_cast<nsXULSlots*>(GetSlots());
|
|
|
|
NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (!slots->mFrameLoader) {
|
2009-08-19 02:09:26 -07:00
|
|
|
slots->mFrameLoader = nsFrameLoader::Create(this);
|
|
|
|
NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
|
2008-03-21 04:18:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return slots->mFrameLoader->LoadFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
|
|
|
|
{
|
|
|
|
*aFrameLoader = nsnull;
|
|
|
|
nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingSlots());
|
|
|
|
if (slots) {
|
|
|
|
NS_IF_ADDREF(*aFrameLoader = slots->mFrameLoader);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-08-11 01:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOtherOwner));
|
|
|
|
NS_ENSURE_TRUE(otherContent, NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
|
|
|
|
nsXULElement* otherEl = FromContent(otherContent);
|
|
|
|
NS_ENSURE_TRUE(otherEl, NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
|
|
|
|
if (otherEl == this) {
|
|
|
|
// nothing to do
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXULSlots *ourSlots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
|
|
|
|
nsXULSlots *otherSlots =
|
|
|
|
static_cast<nsXULSlots*>(otherEl->GetExistingDOMSlots());
|
|
|
|
if (!ourSlots || !ourSlots->mFrameLoader ||
|
|
|
|
!otherSlots || !otherSlots->mFrameLoader) {
|
|
|
|
// Can't handle swapping when there is nothing to swap... yet.
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
ourSlots->mFrameLoader->SwapWithOtherLoader(otherSlots->mFrameLoader,
|
|
|
|
ourSlots->mFrameLoader,
|
|
|
|
otherSlots->mFrameLoader);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement)
|
|
|
|
{
|
|
|
|
for (nsIContent* current = GetParent(); current;
|
|
|
|
current = current->GetParent()) {
|
|
|
|
if (current->NodeInfo()->Equals(nsGkAtoms::listbox,
|
|
|
|
kNameSpaceID_XUL)) {
|
|
|
|
CallQueryInterface(current, aTreeElement);
|
|
|
|
// XXX returning NS_OK because that's what the code used to do;
|
|
|
|
// is that the right thing, though?
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::Focus()
|
|
|
|
{
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(static_cast<nsIContent*>(this));
|
|
|
|
return fm ? fm->SetFocus(this, 0) : NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::Blur()
|
|
|
|
{
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (!ShouldBlur(this))
|
|
|
|
return NS_OK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc)
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIDOMWindow* win = doc->GetWindow();
|
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (win && fm)
|
|
|
|
return fm->ClearFocus(win);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::Click()
|
|
|
|
{
|
|
|
|
if (BoolAttrIsTrue(nsGkAtoms::disabled))
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc = GetCurrentDoc(); // Strong just in case
|
|
|
|
if (doc) {
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(doc);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
// strong ref to PresContext so events don't destroy it
|
|
|
|
nsCOMPtr<nsPresContext> context = shell->GetPresContext();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRBool isCallerChrome = nsContentUtils::IsCallerChrome();
|
|
|
|
|
|
|
|
nsMouseEvent eventDown(isCallerChrome, NS_MOUSE_BUTTON_DOWN,
|
|
|
|
nsnull, nsMouseEvent::eReal);
|
|
|
|
nsMouseEvent eventUp(isCallerChrome, NS_MOUSE_BUTTON_UP,
|
|
|
|
nsnull, nsMouseEvent::eReal);
|
|
|
|
nsMouseEvent eventClick(isCallerChrome, NS_MOUSE_CLICK, nsnull,
|
|
|
|
nsMouseEvent::eReal);
|
|
|
|
|
|
|
|
// send mouse down
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2007-07-08 00:08:04 -07:00
|
|
|
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
context, &eventDown, nsnull, &status);
|
|
|
|
|
|
|
|
// send mouse up
|
|
|
|
status = nsEventStatus_eIgnore; // reset status
|
2007-07-08 00:08:04 -07:00
|
|
|
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
context, &eventUp, nsnull, &status);
|
|
|
|
|
|
|
|
// send mouse click
|
|
|
|
status = nsEventStatus_eIgnore; // reset status
|
2007-07-08 00:08:04 -07:00
|
|
|
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
context, &eventClick, nsnull, &status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// oncommand is fired when an element is clicked...
|
|
|
|
return DoCommand();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXULElement::DoCommand()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDocument> doc = GetCurrentDoc(); // strong just in case
|
|
|
|
if (doc) {
|
2009-06-30 00:56:40 -07:00
|
|
|
nsContentUtils::DispatchXULCommand(this, PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent *
|
|
|
|
nsXULElement::GetBindingParent() const
|
|
|
|
{
|
|
|
|
return mBindingParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXULElement::IsNodeOfType(PRUint32 aFlags) const
|
|
|
|
{
|
2009-08-24 17:51:57 -07:00
|
|
|
return !(aFlags & ~(eCONTENT | eELEMENT | eXUL));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
|
|
|
|
void* aPropertyValue, void* aData)
|
|
|
|
{
|
2007-07-04 08:49:38 -07:00
|
|
|
nsIDOMEventListener* listener =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsIDOMEventListener*>(aPropertyValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!listener) {
|
|
|
|
return;
|
|
|
|
}
|
2009-06-23 03:07:39 -07:00
|
|
|
nsCOMPtr<nsIDOM3EventTarget> target =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_QueryInterface(static_cast<nsINode*>(aObject));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (target) {
|
2009-06-23 03:07:39 -07:00
|
|
|
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
|
|
|
static_cast<nsPIDOMEventTarget*>(aObject)->
|
|
|
|
GetSystemEventGroup(getter_AddRefs(systemGroup));
|
|
|
|
if (systemGroup) {
|
|
|
|
target->RemoveGroupedEventListener(NS_LITERAL_STRING("mousedown"),
|
|
|
|
listener, PR_FALSE, systemGroup);
|
|
|
|
|
|
|
|
target->RemoveGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
|
|
|
|
listener, PR_FALSE, systemGroup);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
NS_RELEASE(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::AddPopupListener(nsIAtom* aName)
|
|
|
|
{
|
2007-07-04 08:49:38 -07:00
|
|
|
// Add a popup listener to the element
|
|
|
|
PRBool isContext = (aName == nsGkAtoms::context ||
|
|
|
|
aName == nsGkAtoms::contextmenu);
|
|
|
|
nsIAtom* listenerAtom = isContext ?
|
|
|
|
nsGkAtoms::contextmenulistener :
|
|
|
|
nsGkAtoms::popuplistener;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventListener> popupListener =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsIDOMEventListener*>(GetProperty(listenerAtom));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (popupListener) {
|
|
|
|
// Popup listener is already installed.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-06-29 15:15:59 -07:00
|
|
|
|
2009-06-23 03:07:39 -07:00
|
|
|
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
|
|
|
GetSystemEventGroup(getter_AddRefs(systemGroup));
|
|
|
|
NS_ENSURE_STATE(systemGroup);
|
|
|
|
|
2007-07-04 08:49:38 -07:00
|
|
|
nsresult rv = NS_NewXULPopupListener(this, isContext,
|
|
|
|
getter_AddRefs(popupListener));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Add the popup as a listener on this element.
|
2009-06-23 03:07:39 -07:00
|
|
|
nsCOMPtr<nsIDOM3EventTarget> target(do_QueryInterface(static_cast<nsIContent *>(this)));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
|
|
|
|
rv = SetProperty(listenerAtom, popupListener, PopupListenerPropertyDtor,
|
|
|
|
PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-04 08:49:38 -07:00
|
|
|
// Want the property to have a reference to the listener.
|
|
|
|
nsIDOMEventListener* listener = nsnull;
|
|
|
|
popupListener.swap(listener);
|
2009-06-23 03:07:39 -07:00
|
|
|
|
|
|
|
if (isContext) {
|
|
|
|
target->AddGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
|
|
|
|
listener, PR_FALSE, systemGroup);
|
|
|
|
} else {
|
|
|
|
target->AddGroupedEventListener(NS_LITERAL_STRING("mousedown"),
|
|
|
|
listener, PR_FALSE, systemGroup);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-06-27 19:48:16 -07:00
|
|
|
PRInt32
|
|
|
|
nsXULElement::IntrinsicState() const
|
|
|
|
{
|
|
|
|
PRInt32 state = nsGenericElement::IntrinsicState();
|
|
|
|
|
|
|
|
const nsIAtom* tag = Tag();
|
|
|
|
if (GetNameSpaceID() == kNameSpaceID_XUL &&
|
|
|
|
(tag == nsGkAtoms::textbox || tag == nsGkAtoms::textarea) &&
|
|
|
|
!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
|
|
|
|
state |= NS_EVENT_STATE_MOZ_READWRITE;
|
|
|
|
state &= ~NS_EVENT_STATE_MOZ_READONLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsGenericElement::nsAttrInfo
|
|
|
|
nsXULElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom *aName) const
|
|
|
|
{
|
|
|
|
|
|
|
|
nsAttrInfo info(nsGenericElement::GetAttrInfo(aNamespaceID, aName));
|
|
|
|
if (!info.mValue) {
|
|
|
|
nsXULPrototypeAttribute *protoattr =
|
|
|
|
FindPrototypeAttribute(aNamespaceID, aName);
|
|
|
|
if (protoattr) {
|
|
|
|
return nsAttrInfo(&protoattr->mName, &protoattr->mValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute *
|
|
|
|
nsXULElement::FindPrototypeAttribute(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aLocalName) const
|
|
|
|
{
|
|
|
|
if (!mPrototype) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 i, count = mPrototype->mNumAttributes;
|
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
// Common case so optimize for this
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
nsXULPrototypeAttribute *protoattr = &mPrototype->mAttributes[i];
|
|
|
|
if (protoattr->mName.Equals(aLocalName)) {
|
|
|
|
return protoattr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
nsXULPrototypeAttribute *protoattr = &mPrototype->mAttributes[i];
|
|
|
|
if (protoattr->mName.Equals(aLocalName, aNamespaceID)) {
|
|
|
|
return protoattr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsXULElement::MakeHeavyweight()
|
|
|
|
{
|
|
|
|
if (!mPrototype)
|
|
|
|
return NS_OK; // already heavyweight
|
|
|
|
|
|
|
|
nsRefPtr<nsXULPrototypeElement> proto;
|
|
|
|
proto.swap(mPrototype);
|
|
|
|
|
|
|
|
PRBool hadAttributes = mAttrsAndChildren.AttrCount() > 0;
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
nsresult rv;
|
|
|
|
for (i = 0; i < proto->mNumAttributes; ++i) {
|
|
|
|
nsXULPrototypeAttribute* protoattr = &proto->mAttributes[i];
|
|
|
|
|
|
|
|
// We might have a local value for this attribute, in which case
|
|
|
|
// we don't want to copy the prototype's value.
|
|
|
|
if (hadAttributes &&
|
|
|
|
mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(),
|
|
|
|
protoattr->mName.NamespaceID())) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
|
|
|
|
nsAttrValue attrValue(protoattr->mValue);
|
2007-04-29 10:58:52 -07:00
|
|
|
|
|
|
|
// Style rules need to be cloned.
|
|
|
|
if (attrValue.Type() == nsAttrValue::eCSSStyleRule) {
|
|
|
|
nsCOMPtr<nsICSSRule> ruleClone;
|
|
|
|
rv = attrValue.GetCSSStyleRuleValue()->Clone(*getter_AddRefs(ruleClone));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsICSSStyleRule> styleRule = do_QueryInterface(ruleClone);
|
|
|
|
attrValue.SetTo(styleRule);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (protoattr->mName.IsAtom()) {
|
|
|
|
rv = mAttrsAndChildren.SetAndTakeAttr(protoattr->mName.Atom(), attrValue);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rv = mAttrsAndChildren.SetAndTakeAttr(protoattr->mName.NodeInfo(),
|
|
|
|
attrValue);
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULElement::HideWindowChrome(PRBool aShouldHide)
|
|
|
|
{
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc || doc->GetRootContent() != this)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
2007-08-20 23:44:43 -07:00
|
|
|
// only top level chrome documents can hide the window chrome
|
2008-10-04 13:00:09 -07:00
|
|
|
if (!doc->IsRootDisplayDocument())
|
2007-08-20 23:44:43 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = doc->GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (shell) {
|
2007-07-08 00:08:04 -07:00
|
|
|
nsIContent* content = static_cast<nsIContent*>(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIFrame* frame = shell->GetPrimaryFrameFor(content);
|
|
|
|
|
|
|
|
nsPresContext *presContext = shell->GetPresContext();
|
|
|
|
|
2007-08-20 23:44:43 -07:00
|
|
|
if (frame && presContext && presContext->IsChrome()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIView* view = frame->GetClosestView();
|
|
|
|
|
|
|
|
if (view) {
|
|
|
|
nsIWidget* w = view->GetWidget();
|
|
|
|
NS_ENSURE_STATE(w);
|
|
|
|
w->HideWindowChrome(aShouldHide);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-10-29 21:03:42 -07:00
|
|
|
void
|
2008-05-02 04:32:50 -07:00
|
|
|
nsXULElement::SetTitlebarColor(nscolor aColor, PRBool aActive)
|
2007-10-29 21:03:42 -07:00
|
|
|
{
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc || doc->GetRootContent() != this) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only top level chrome documents can set the titlebar color
|
2008-10-04 13:00:09 -07:00
|
|
|
if (doc->IsRootDisplayDocument()) {
|
2007-10-29 21:03:42 -07:00
|
|
|
nsCOMPtr<nsISupports> container = doc->GetContainer();
|
|
|
|
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
|
|
|
|
if (baseWindow) {
|
|
|
|
nsCOMPtr<nsIWidget> mainWidget;
|
|
|
|
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
|
|
|
|
if (mainWidget) {
|
2008-05-02 04:32:50 -07:00
|
|
|
mainWidget->SetWindowTitlebarColor(aColor, aActive);
|
2007-10-29 21:03:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRBool
|
|
|
|
nsXULElement::BoolAttrIsTrue(nsIAtom* aName)
|
|
|
|
{
|
|
|
|
const nsAttrValue* attr =
|
|
|
|
FindLocalOrProtoAttr(kNameSpaceID_None, aName);
|
|
|
|
|
|
|
|
return attr && attr->Type() == nsAttrValue::eAtom &&
|
|
|
|
attr->GetAtomValue() == nsGkAtoms::_true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULElement::RecompileScriptEventListeners()
|
|
|
|
{
|
|
|
|
PRInt32 i, count = mAttrsAndChildren.AttrCount();
|
|
|
|
PRBool haveLocalAttributes = (count > 0);
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
|
|
|
|
|
|
|
|
// Eventlistenener-attributes are always in the null namespace
|
|
|
|
if (!name->IsAtom()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *attr = name->Atom();
|
2007-04-02 10:17:36 -07:00
|
|
|
if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
GetAttr(kNameSpaceID_None, attr, value);
|
|
|
|
AddScriptEventListener(attr, value, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mPrototype) {
|
|
|
|
// If we have a prototype, the node we are binding to should
|
|
|
|
// have the same script-type - otherwise we will compile the
|
|
|
|
// event handlers incorrectly.
|
|
|
|
NS_ASSERTION(mPrototype->mScriptTypeID == GetScriptTypeID(),
|
|
|
|
"Prototype and node confused about default language?");
|
|
|
|
|
|
|
|
count = mPrototype->mNumAttributes;
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
const nsAttrName &name = mPrototype->mAttributes[i].mName;
|
|
|
|
|
|
|
|
// Eventlistenener-attributes are always in the null namespace
|
|
|
|
if (!name.IsAtom()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *attr = name.Atom();
|
|
|
|
|
|
|
|
// Don't clobber a locally modified attribute.
|
|
|
|
if (haveLocalAttributes && mAttrsAndChildren.GetAttr(attr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-04-02 10:17:36 -07:00
|
|
|
if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
GetAttr(kNameSpaceID_None, attr, value);
|
|
|
|
AddScriptEventListener(attr, value, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-29 06:45:07 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode)
|
2007-11-01 15:51:57 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXULPrototypeNode)
|
|
|
|
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
|
|
|
|
static_cast<nsXULPrototypeElement*>(tmp)->Unlink();
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
2007-05-24 07:10:02 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode)
|
|
|
|
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
|
|
|
|
nsXULPrototypeElement *elem =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsXULPrototypeElement*>(tmp);
|
2008-03-28 07:09:00 -07:00
|
|
|
cb.NoteXPCOMChild(elem->mNodeInfo);
|
2007-05-24 07:10:02 -07:00
|
|
|
PRUint32 i;
|
2008-03-28 07:09:00 -07:00
|
|
|
for (i = 0; i < elem->mNumAttributes; ++i) {
|
|
|
|
const nsAttrName& name = elem->mAttributes[i].mName;
|
|
|
|
if (!name.IsAtom())
|
|
|
|
cb.NoteXPCOMChild(name.NodeInfo());
|
|
|
|
}
|
2008-10-08 04:41:52 -07:00
|
|
|
for (i = 0; i < elem->mChildren.Length(); ++i) {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(elem->mChildren[i].get(),
|
2008-03-17 16:11:08 -07:00
|
|
|
nsXULPrototypeNode,
|
|
|
|
"mChildren[i]")
|
2007-05-24 07:10:02 -07:00
|
|
|
}
|
|
|
|
}
|
2007-10-29 06:45:07 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode)
|
|
|
|
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
|
|
|
|
nsXULPrototypeElement *elem =
|
|
|
|
static_cast<nsXULPrototypeElement*>(tmp);
|
|
|
|
if (elem->mHoldsScriptObject) {
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < elem->mNumAttributes; ++i) {
|
|
|
|
void *handler = elem->mAttributes[i].mEventHandler;
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(elem->mScriptTypeID,
|
|
|
|
handler)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-05-24 07:10:02 -07:00
|
|
|
else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
|
2007-10-29 06:45:07 -07:00
|
|
|
nsXULPrototypeScript *script =
|
|
|
|
static_cast<nsXULPrototypeScript*>(tmp);
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(script->mScriptObject.mLangID,
|
|
|
|
script->mScriptObject.mObject)
|
2007-05-24 07:10:02 -07:00
|
|
|
}
|
2007-10-29 06:45:07 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
2008-01-29 18:05:43 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN_NATIVE(nsXULPrototypeNode, AddRef)
|
|
|
|
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
|
|
|
|
static_cast<nsXULPrototypeElement*>(tmp)->UnlinkJSObjects();
|
|
|
|
}
|
|
|
|
else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
|
|
|
|
static_cast<nsXULPrototypeScript*>(tmp)->UnlinkJSObjects();
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_END
|
|
|
|
//NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
|
2007-05-24 07:10:02 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsXULPrototypeAttribute
|
|
|
|
//
|
|
|
|
|
|
|
|
nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsXULPrototypeAttribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsXULPrototypeElement
|
|
|
|
//
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Write basic prototype data
|
|
|
|
rv = aStream->Write32(mType);
|
|
|
|
|
|
|
|
// Write script language
|
|
|
|
rv |= aStream->Write32(mScriptTypeID);
|
|
|
|
|
|
|
|
// Write Node Info
|
|
|
|
PRInt32 index = aNodeInfos->IndexOf(mNodeInfo);
|
|
|
|
NS_ASSERTION(index >= 0, "unknown nsINodeInfo index");
|
|
|
|
rv |= aStream->Write32(index);
|
|
|
|
|
|
|
|
// Write Attributes
|
|
|
|
rv |= aStream->Write32(mNumAttributes);
|
|
|
|
|
|
|
|
nsAutoString attributeValue;
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < mNumAttributes; ++i) {
|
|
|
|
nsCOMPtr<nsINodeInfo> ni;
|
|
|
|
if (mAttributes[i].mName.IsAtom()) {
|
2008-09-12 15:32:18 -07:00
|
|
|
ni = mNodeInfo->NodeInfoManager()->
|
2007-03-22 10:30:00 -07:00
|
|
|
GetNodeInfo(mAttributes[i].mName.Atom(), nsnull,
|
2008-09-12 15:32:18 -07:00
|
|
|
kNameSpaceID_None);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(ni, "the nodeinfo should already exist");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ni = mAttributes[i].mName.NodeInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
index = aNodeInfos->IndexOf(ni);
|
|
|
|
NS_ASSERTION(index >= 0, "unknown nsINodeInfo index");
|
|
|
|
rv |= aStream->Write32(index);
|
|
|
|
|
|
|
|
mAttributes[i].mValue.ToString(attributeValue);
|
|
|
|
rv |= aStream->WriteWStringZ(attributeValue.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now write children
|
2008-10-08 04:41:52 -07:00
|
|
|
rv |= aStream->Write32(PRUint32(mChildren.Length()));
|
|
|
|
for (i = 0; i < mChildren.Length(); i++) {
|
|
|
|
nsXULPrototypeNode* child = mChildren[i].get();
|
2007-03-22 10:30:00 -07:00
|
|
|
switch (child->mType) {
|
|
|
|
case eType_Element:
|
|
|
|
case eType_Text:
|
|
|
|
case eType_PI:
|
|
|
|
rv |= child->Serialize(aStream, aGlobal, aNodeInfos);
|
|
|
|
break;
|
|
|
|
case eType_Script:
|
|
|
|
rv |= aStream->Write32(child->mType);
|
2007-07-08 00:08:04 -07:00
|
|
|
nsXULPrototypeScript* script = static_cast<nsXULPrototypeScript*>(child);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
rv |= aStream->Write32(script->mScriptObject.mLangID);
|
|
|
|
|
|
|
|
rv |= aStream->Write8(script->mOutOfLine);
|
|
|
|
if (! script->mOutOfLine) {
|
|
|
|
rv |= script->Serialize(aStream, aGlobal, aNodeInfos);
|
|
|
|
} else {
|
|
|
|
rv |= aStream->WriteCompoundObject(script->mSrcURI,
|
|
|
|
NS_GET_IID(nsIURI),
|
|
|
|
PR_TRUE);
|
|
|
|
|
|
|
|
if (script->mScriptObject.mObject) {
|
|
|
|
// This may return NS_OK without muxing script->mSrcURI's
|
|
|
|
// data into the FastLoad file, in the case where that
|
|
|
|
// muxed document is already there (written by a prior
|
|
|
|
// session, or by an earlier FastLoad episode during this
|
|
|
|
// session).
|
|
|
|
rv |= script->SerializeOutOfLine(aStream, aGlobal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
nsIURI* aDocumentURI,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNodeInfos, "missing nodeinfo array");
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Read script language
|
2007-09-18 01:38:24 -07:00
|
|
|
PRUint32 scriptId = 0;
|
|
|
|
rv = aStream->Read32(&scriptId);
|
|
|
|
mScriptTypeID = scriptId;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Read Node Info
|
|
|
|
PRUint32 number;
|
|
|
|
rv |= aStream->Read32(&number);
|
|
|
|
mNodeInfo = aNodeInfos->SafeObjectAt(number);
|
|
|
|
if (!mNodeInfo)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
// Read Attributes
|
|
|
|
rv |= aStream->Read32(&number);
|
|
|
|
mNumAttributes = PRInt32(number);
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
if (mNumAttributes > 0) {
|
|
|
|
mAttributes = new nsXULPrototypeAttribute[mNumAttributes];
|
|
|
|
if (! mAttributes)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
nsAutoString attributeValue;
|
|
|
|
for (i = 0; i < mNumAttributes; ++i) {
|
|
|
|
rv |= aStream->Read32(&number);
|
|
|
|
nsINodeInfo* ni = aNodeInfos->SafeObjectAt(number);
|
|
|
|
if (!ni)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
mAttributes[i].mName.SetTo(ni);
|
|
|
|
|
|
|
|
rv |= aStream->ReadString(attributeValue);
|
|
|
|
rv |= SetAttrAt(i, attributeValue, aDocumentURI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv |= aStream->Read32(&number);
|
2008-10-08 04:41:52 -07:00
|
|
|
PRUint32 numChildren = PRInt32(number);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-08 04:41:52 -07:00
|
|
|
if (numChildren > 0) {
|
|
|
|
if (!mChildren.SetCapacity(numChildren))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2008-10-08 04:41:52 -07:00
|
|
|
for (i = 0; i < numChildren; i++) {
|
2007-03-22 10:30:00 -07:00
|
|
|
rv |= aStream->Read32(&number);
|
|
|
|
Type childType = (Type)number;
|
|
|
|
|
2008-10-08 04:41:52 -07:00
|
|
|
nsRefPtr<nsXULPrototypeNode> child;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
switch (childType) {
|
|
|
|
case eType_Element:
|
|
|
|
child = new nsXULPrototypeElement();
|
|
|
|
if (! child)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
child->mType = childType;
|
|
|
|
|
|
|
|
rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
|
|
|
|
aNodeInfos);
|
|
|
|
break;
|
|
|
|
case eType_Text:
|
|
|
|
child = new nsXULPrototypeText();
|
|
|
|
if (! child)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
child->mType = childType;
|
|
|
|
|
|
|
|
rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
|
|
|
|
aNodeInfos);
|
|
|
|
break;
|
|
|
|
case eType_PI:
|
|
|
|
child = new nsXULPrototypePI();
|
|
|
|
if (! child)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
child->mType = childType;
|
|
|
|
|
|
|
|
rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
|
|
|
|
aNodeInfos);
|
|
|
|
break;
|
|
|
|
case eType_Script: {
|
|
|
|
PRUint32 langID = nsIProgrammingLanguage::UNKNOWN;
|
|
|
|
rv |= aStream->Read32(&langID);
|
|
|
|
|
|
|
|
// language version/options obtained during deserialization.
|
|
|
|
nsXULPrototypeScript* script = new nsXULPrototypeScript(langID, 0, 0);
|
|
|
|
if (! script)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
child = script;
|
|
|
|
child->mType = childType;
|
|
|
|
|
|
|
|
rv |= aStream->Read8(&script->mOutOfLine);
|
|
|
|
if (! script->mOutOfLine) {
|
|
|
|
rv |= script->Deserialize(aStream, aGlobal, aDocumentURI,
|
|
|
|
aNodeInfos);
|
|
|
|
} else {
|
|
|
|
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(script->mSrcURI));
|
|
|
|
|
|
|
|
rv |= script->DeserializeOutOfLine(aStream, aGlobal);
|
|
|
|
}
|
|
|
|
// If we failed to deserialize, consider deleting 'script'?
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
NS_NOTREACHED("Unexpected child type!");
|
|
|
|
rv = NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2008-10-08 04:41:52 -07:00
|
|
|
mChildren.AppendElement(child);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Oh dear. Something failed during the deserialization.
|
|
|
|
// We don't know what. But likely consequences of failed
|
|
|
|
// deserializations included calls to |AbortFastLoads| which
|
|
|
|
// shuts down the FastLoadService and closes our streams.
|
|
|
|
// If that happens, next time through this loop, we die a messy
|
|
|
|
// death. So, let's just fail now, and propagate that failure
|
|
|
|
// upward so that the ChromeProtocolHandler knows it can't use
|
|
|
|
// a cached chrome channel for this.
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
|
|
|
|
nsIURI* aDocumentURI)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aPos < mNumAttributes, "out-of-bounds");
|
|
|
|
|
|
|
|
// WARNING!!
|
|
|
|
// This code is largely duplicated in nsXULElement::SetAttr.
|
|
|
|
// Any changes should be made to both functions.
|
|
|
|
|
|
|
|
if (!mNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
|
|
|
|
mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAttributes[aPos].mName.Equals(nsGkAtoms::id) &&
|
|
|
|
!aValue.IsEmpty()) {
|
2007-09-18 01:38:24 -07:00
|
|
|
mHasIdAttribute = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
// Store id as atom.
|
|
|
|
// id="" means that the element has no id. Not that it has
|
|
|
|
// emptystring as id.
|
|
|
|
mAttributes[aPos].mValue.ParseAtom(aValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (mAttributes[aPos].mName.Equals(nsGkAtoms::_class)) {
|
2007-09-18 01:38:24 -07:00
|
|
|
mHasClassAttribute = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
// Compute the element's class list
|
|
|
|
mAttributes[aPos].mValue.ParseAtomArray(aValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (mAttributes[aPos].mName.Equals(nsGkAtoms::style)) {
|
2007-09-18 01:38:24 -07:00
|
|
|
mHasStyleAttribute = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
// Parse the element's 'style' attribute
|
|
|
|
nsCOMPtr<nsICSSStyleRule> rule;
|
|
|
|
nsICSSParser* parser = GetCSSParser();
|
|
|
|
NS_ENSURE_TRUE(parser, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
// XXX Get correct Base URI (need GetBaseURI on *prototype* element)
|
|
|
|
parser->ParseStyleAttribute(aValue, aDocumentURI, aDocumentURI,
|
2007-05-02 18:15:53 -07:00
|
|
|
// This is basically duplicating what
|
|
|
|
// nsINode::NodePrincipal() does
|
|
|
|
mNodeInfo->NodeInfoManager()->
|
|
|
|
DocumentPrincipal(),
|
2007-03-22 10:30:00 -07:00
|
|
|
getter_AddRefs(rule));
|
|
|
|
if (rule) {
|
|
|
|
mAttributes[aPos].mValue.SetTo(rule);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
// Don't abort if parsing failed, it could just be malformed css.
|
|
|
|
}
|
|
|
|
|
|
|
|
mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-10-29 06:45:07 -07:00
|
|
|
void
|
2008-01-29 18:05:43 -08:00
|
|
|
nsXULPrototypeElement::UnlinkJSObjects()
|
2007-10-29 06:45:07 -07:00
|
|
|
{
|
|
|
|
if (mHoldsScriptObject) {
|
|
|
|
nsContentUtils::DropScriptObjects(mScriptTypeID, this,
|
|
|
|
&NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
|
|
|
|
mHoldsScriptObject = PR_FALSE;
|
|
|
|
}
|
2008-01-29 18:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXULPrototypeElement::Unlink()
|
|
|
|
{
|
2007-10-29 06:45:07 -07:00
|
|
|
mNumAttributes = 0;
|
|
|
|
delete[] mAttributes;
|
|
|
|
mAttributes = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsXULPrototypeScript
|
|
|
|
//
|
|
|
|
|
|
|
|
nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, PRUint32 aVersion)
|
|
|
|
: nsXULPrototypeNode(eType_Script),
|
|
|
|
mLineNo(aLineNo),
|
|
|
|
mSrcLoading(PR_FALSE),
|
|
|
|
mOutOfLine(PR_TRUE),
|
|
|
|
mSrcLoadWaiters(nsnull),
|
|
|
|
mLangVersion(aVersion),
|
|
|
|
mScriptObject(aLangID)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
|
|
|
|
"The language ID must be known and constant");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsXULPrototypeScript::~nsXULPrototypeScript()
|
|
|
|
{
|
2008-01-29 18:05:43 -08:00
|
|
|
UnlinkJSObjects();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsIScriptContext *context = aGlobal->GetScriptContext(
|
|
|
|
mScriptObject.mLangID);
|
|
|
|
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
|
|
|
|
!mScriptObject.mObject,
|
|
|
|
"script source still loading when serializing?!");
|
|
|
|
if (!mScriptObject.mObject)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Write basic prototype data
|
|
|
|
nsresult rv;
|
|
|
|
rv = aStream->Write32(mLineNo);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = aStream->Write32(mLangVersion);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// And delegate the writing to the nsIScriptContext
|
|
|
|
rv = context->Serialize(aStream, mScriptObject.mObject);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal)
|
|
|
|
{
|
|
|
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
|
|
|
if (!cache)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ASSERTION(cache->IsEnabled(),
|
|
|
|
"writing to the FastLoad file, but the XUL cache is off?");
|
|
|
|
|
|
|
|
nsIFastLoadService* fastLoadService = cache->GetFastLoadService();
|
|
|
|
if (!fastLoadService)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
|
|
|
nsCAutoString urispec;
|
|
|
|
nsresult rv = mSrcURI->GetAsciiSpec(urispec);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
PRBool exists = PR_FALSE;
|
|
|
|
fastLoadService->HasMuxedDocument(urispec.get(), &exists);
|
|
|
|
/* return will be NS_OK from GetAsciiSpec.
|
|
|
|
* that makes no sense.
|
|
|
|
* nor does returning NS_OK from HasMuxedDocument.
|
|
|
|
* XXX return something meaningful.
|
|
|
|
*/
|
|
|
|
if (exists)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// Allow callers to pass null for aStream, meaning
|
|
|
|
// "use the FastLoad service's default output stream."
|
|
|
|
// See nsXULDocument.cpp for one use of this.
|
|
|
|
nsCOMPtr<nsIObjectOutputStream> objectOutput = aStream;
|
|
|
|
if (! objectOutput) {
|
|
|
|
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
|
|
|
if (! objectOutput)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = fastLoadService->
|
|
|
|
StartMuxedDocument(mSrcURI, urispec.get(),
|
|
|
|
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
|
|
|
NS_ASSERTION(rv != NS_ERROR_NOT_AVAILABLE, "reading FastLoad?!");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> oldURI;
|
|
|
|
rv |= fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
|
|
|
|
rv |= Serialize(objectOutput, aGlobal, nsnull);
|
|
|
|
rv |= fastLoadService->EndMuxedDocument(mSrcURI);
|
|
|
|
|
|
|
|
if (oldURI) {
|
|
|
|
nsCOMPtr<nsIURI> tempURI;
|
|
|
|
rv |= fastLoadService->
|
|
|
|
SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
cache->AbortFastLoads();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
nsIURI* aDocumentURI,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
NS_TIMELINE_MARK_FUNCTION("chrome script deserialize");
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
|
|
|
|
!mScriptObject.mObject,
|
|
|
|
"prototype script not well-initialized when deserializing?!");
|
|
|
|
|
|
|
|
// Read basic prototype data
|
|
|
|
aStream->Read32(&mLineNo);
|
|
|
|
aStream->Read32(&mLangVersion);
|
|
|
|
|
|
|
|
nsIScriptContext *context = aGlobal->GetScriptContext(
|
|
|
|
mScriptObject.mLangID);
|
|
|
|
NS_ASSERTION(context != nsnull, "Have no context for deserialization");
|
|
|
|
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
|
|
|
|
nsScriptObjectHolder newScriptObject(context);
|
|
|
|
rv = context->Deserialize(aStream, newScriptObject);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Language deseralization failed");
|
|
|
|
return rv;
|
|
|
|
}
|
2007-10-29 06:45:07 -07:00
|
|
|
Set(newScriptObject);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
|
|
|
nsIScriptGlobalObject* aGlobal)
|
|
|
|
{
|
|
|
|
// Keep track of FastLoad failure via rv, so we can
|
|
|
|
// AbortFastLoads if things look bad.
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
|
|
|
nsIFastLoadService* fastLoadService = cache->GetFastLoadService();
|
|
|
|
|
|
|
|
// Allow callers to pass null for aInput, meaning
|
|
|
|
// "use the FastLoad service's default input stream."
|
|
|
|
// See nsXULContentSink.cpp for one use of this.
|
|
|
|
nsCOMPtr<nsIObjectInputStream> objectInput = aInput;
|
|
|
|
if (! objectInput && fastLoadService)
|
|
|
|
fastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
|
|
|
|
|
|
|
if (objectInput) {
|
|
|
|
PRBool useXULCache = PR_TRUE;
|
|
|
|
if (mSrcURI) {
|
|
|
|
// NB: we must check the XUL script cache early, to avoid
|
|
|
|
// multiple deserialization attempts for a given script, which
|
|
|
|
// would exhaust the multiplexed stream containing the singly
|
|
|
|
// serialized script. Note that nsXULDocument::LoadScript
|
|
|
|
// checks the XUL script cache too, in order to handle the
|
|
|
|
// serialization case.
|
|
|
|
//
|
|
|
|
// We need do this only for <script src='strres.js'> and the
|
|
|
|
// like, i.e., out-of-line scripts that are included by several
|
|
|
|
// different XUL documents multiplexed in the FastLoad file.
|
|
|
|
useXULCache = cache->IsEnabled();
|
|
|
|
|
|
|
|
if (useXULCache) {
|
|
|
|
PRUint32 newLangID = nsIProgrammingLanguage::UNKNOWN;
|
|
|
|
void *newScriptObject = cache->GetScript(mSrcURI, &newLangID);
|
|
|
|
if (newScriptObject) {
|
|
|
|
// Things may blow here if we simply change the script
|
|
|
|
// language - other code may already have pre-fetched the
|
|
|
|
// global for the language. (You can see this code by
|
|
|
|
// setting langID to UNKNOWN in the nsXULPrototypeScript
|
|
|
|
// ctor and not setting it until the scriptObject is set -
|
|
|
|
// code that pre-fetches these globals will then start
|
|
|
|
// asserting.)
|
|
|
|
if (mScriptObject.mLangID != newLangID) {
|
|
|
|
NS_ERROR("XUL cache gave different language?");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2007-10-29 06:45:07 -07:00
|
|
|
Set(newScriptObject);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! mScriptObject.mObject) {
|
|
|
|
nsCOMPtr<nsIURI> oldURI;
|
|
|
|
|
|
|
|
if (mSrcURI) {
|
|
|
|
nsCAutoString spec;
|
|
|
|
mSrcURI->GetAsciiSpec(spec);
|
|
|
|
rv = fastLoadService->StartMuxedDocument(mSrcURI, spec.get(),
|
|
|
|
nsIFastLoadService::NS_FASTLOAD_READ);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
rv = fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
|
|
|
|
} else {
|
|
|
|
// An inline script: check FastLoad multiplexing direction
|
|
|
|
// and skip Deserialize if we're not reading from a
|
|
|
|
// muxed stream to get inline objects that are contained in
|
|
|
|
// the current document.
|
|
|
|
PRInt32 direction;
|
|
|
|
fastLoadService->GetDirection(&direction);
|
|
|
|
if (direction != nsIFastLoadService::NS_FASTLOAD_READ)
|
|
|
|
rv = NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We do reflect errors into rv, but our caller may want to
|
|
|
|
// ignore our return value, because mScriptObject will be null
|
|
|
|
// after any error, and that suffices to cause the script to
|
|
|
|
// be reloaded (from the src= URI, if any) and recompiled.
|
|
|
|
// We're better off slow-loading than bailing out due to a
|
|
|
|
// FastLoad error.
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
rv = Deserialize(objectInput, aGlobal, nsnull, nsnull);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && mSrcURI) {
|
|
|
|
rv = fastLoadService->EndMuxedDocument(mSrcURI);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && oldURI) {
|
|
|
|
nsCOMPtr<nsIURI> tempURI;
|
|
|
|
rv = fastLoadService->SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
|
|
|
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv) && (!tempURI || tempURI == mSrcURI),
|
|
|
|
"not currently deserializing into the script we thought we were!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (useXULCache && mSrcURI) {
|
|
|
|
PRBool isChrome = PR_FALSE;
|
|
|
|
mSrcURI->SchemeIs("chrome", &isChrome);
|
|
|
|
if (isChrome) {
|
|
|
|
cache->PutScript(mSrcURI,
|
|
|
|
mScriptObject.mLangID,
|
|
|
|
mScriptObject.mObject);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If mSrcURI is not in the FastLoad multiplex,
|
|
|
|
// rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
|
|
|
|
// update the FastLoad file to hold a serialization of
|
|
|
|
// this script, once it has finished loading.
|
|
|
|
if (rv != NS_ERROR_NOT_AVAILABLE)
|
|
|
|
cache->AbortFastLoads();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
|
|
|
PRInt32 aTextLength,
|
|
|
|
nsIURI* aURI,
|
|
|
|
PRUint32 aLineNo,
|
|
|
|
nsIDocument* aDocument,
|
|
|
|
nsIScriptGlobalObjectOwner* aGlobalOwner)
|
|
|
|
{
|
|
|
|
// We'll compile the script using the prototype document's special
|
|
|
|
// script object as the parent. This ensures that we won't end up
|
|
|
|
// with an uncollectable reference.
|
|
|
|
//
|
|
|
|
// Compiling it using (for example) the first document's global
|
|
|
|
// object would cause JS to keep a reference via the __proto__ or
|
|
|
|
// __parent__ pointer to the first document's global. If that
|
|
|
|
// happened, our script object would reference the first document,
|
|
|
|
// and the first document would indirectly reference the prototype
|
|
|
|
// document because it keeps the prototype cache alive. Circularity!
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Use the prototype document's special context
|
|
|
|
nsIScriptContext *context;
|
|
|
|
|
|
|
|
{
|
|
|
|
nsIScriptGlobalObject* global = aGlobalOwner->GetScriptGlobalObject();
|
|
|
|
NS_ASSERTION(global != nsnull, "prototype doc has no script global");
|
|
|
|
if (! global)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
context = global->GetScriptContext(mScriptObject.mLangID);
|
|
|
|
NS_ASSERTION(context != nsnull, "no context for script global");
|
|
|
|
if (! context)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCAutoString urlspec;
|
2008-11-13 16:00:11 -08:00
|
|
|
nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Ok, compile it to create a prototype script object!
|
|
|
|
|
|
|
|
nsScriptObjectHolder newScriptObject(context);
|
|
|
|
rv = context->CompileScript(aText,
|
|
|
|
aTextLength,
|
|
|
|
nsnull,
|
|
|
|
// Use the enclosing document's principal
|
|
|
|
// XXX is this right? or should we use the
|
|
|
|
// protodoc's?
|
2008-03-21 22:03:57 -07:00
|
|
|
// If we start using the protodoc's, make sure
|
|
|
|
// the DowngradePrincipalIfNeeded stuff in
|
|
|
|
// nsXULDocument::OnStreamComplete still works!
|
2007-03-22 10:30:00 -07:00
|
|
|
aDocument->NodePrincipal(),
|
|
|
|
urlspec.get(),
|
|
|
|
aLineNo,
|
|
|
|
mLangVersion,
|
|
|
|
newScriptObject);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
2007-10-29 06:45:07 -07:00
|
|
|
Set(newScriptObject);
|
2007-03-22 10:30:00 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsXULPrototypeText
|
|
|
|
//
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Write basic prototype data
|
|
|
|
rv = aStream->Write32(mType);
|
|
|
|
|
|
|
|
rv |= aStream->WriteWStringZ(mValue.get());
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
nsIURI* aDocumentURI,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = aStream->ReadString(mValue);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsXULPrototypePI
|
|
|
|
//
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypePI::Serialize(nsIObjectOutputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Write basic prototype data
|
|
|
|
rv = aStream->Write32(mType);
|
|
|
|
|
|
|
|
rv |= aStream->WriteWStringZ(mTarget.get());
|
|
|
|
rv |= aStream->WriteWStringZ(mData.get());
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXULPrototypePI::Deserialize(nsIObjectInputStream* aStream,
|
|
|
|
nsIScriptGlobalObject* aGlobal,
|
|
|
|
nsIURI* aDocumentURI,
|
|
|
|
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = aStream->ReadString(mTarget);
|
|
|
|
rv |= aStream->ReadString(mData);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|