Mozilla/mozilla/layout/html/content/src/nsHTMLGenericContent.cpp
troy%netscape.com cb9d4c2248 Added release of content object in SetDocumentInChildrenOf. This fixes a
memory leak


git-svn-id: svn://10.0.0.236/trunk@13787 18797224-902f-48f8-a5cc-f745e15eee43
1998-10-31 04:00:25 +00:00

2573 lines
68 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nsHTMLGenericContent.h"
#include "nsIAtom.h"
#include "nsIContentDelegate.h"
#include "nsICSSParser.h"
#include "nsIDocument.h"
#include "nsIDOMAttribute.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsIEventListenerManager.h"
#include "nsIHTMLAttributes.h"
#include "nsIHTMLStyleSheet.h"
#include "nsIHTMLDocument.h"
#include "nsIHTMLContent.h"
#include "nsILinkHandler.h"
#include "nsIScriptContextOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectOwner.h"
#include "nsISizeOfHandler.h"
#include "nsIStyleContext.h"
#include "nsIStyleRule.h"
#include "nsISupportsArray.h"
#include "nsIURL.h"
#include "nsStyleConsts.h"
#include "nsXIFConverter.h"
#include "nsFrame.h"
#include "nsString.h"
#include "nsHTMLAtoms.h"
#include "nsDOMEventsIIDs.h"
#include "nsCSSBlockFrame.h"
#include "nsCSSInlineFrame.h"
#include "nsIEventStateManager.h"
#include "nsDOMEvent.h"
#include "nsIPrivateDOMEvent.h"
#include "prprf.h"
// XXX todo: add in missing out-of-memory checks
NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);
NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID);
NS_DEFINE_IID(kIDOMHTMLElementIID, NS_IDOMHTMLELEMENT_IID);
NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID);
NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
//NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID);
static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID);
static NS_DEFINE_IID(kIDOMAttributeIID, NS_IDOMATTRIBUTE_IID);
static NS_DEFINE_IID(kIDOMNamedNodeMapIID, NS_IDOMNAMEDNODEMAP_IID);
static NS_DEFINE_IID(kIPrivateDOMEventIID, NS_IPRIVATEDOMEVENT_IID);
static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID);
static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID);
// Attribute helper class used to wrap up an attribute with a dom
// object that implements nsIDOMAttribute and nsIDOMNode and
// nsIScriptObjectOwner
class DOMAttribute : public nsIDOMAttribute, public nsIScriptObjectOwner {
public:
DOMAttribute(const nsString &aName, const nsString &aValue);
~DOMAttribute();
NS_DECL_ISUPPORTS
NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject);
NS_IMETHOD ResetScriptObject();
// nsIDOMAttribute interface
NS_IMETHOD GetSpecified(PRBool* aSpecified);
NS_IMETHOD SetSpecified(PRBool aSpecified);
NS_IMETHOD GetName(nsString& aReturn);
NS_IMETHOD GetValue(nsString& aReturn);
// nsIDOMNode interface
NS_IMETHOD GetNodeName(nsString& aNodeName);
NS_IMETHOD GetNodeValue(nsString& aNodeValue);
NS_IMETHOD SetNodeValue(const nsString& aNodeValue);
NS_IMETHOD GetNodeType(PRInt32* aNodeType);
NS_IMETHOD GetParentNode(nsIDOMNode** aParentNode);
NS_IMETHOD GetChildNodes(nsIDOMNodeList** aChildNodes);
NS_IMETHOD GetHasChildNodes(PRBool* aHasChildNodes);
NS_IMETHOD GetFirstChild(nsIDOMNode** aFirstChild);
NS_IMETHOD GetLastChild(nsIDOMNode** aLastChild);
NS_IMETHOD GetPreviousSibling(nsIDOMNode** aPreviousSibling);
NS_IMETHOD GetNextSibling(nsIDOMNode** aNextSibling);
NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes);
NS_IMETHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
nsIDOMNode** aReturn);
NS_IMETHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn);
NS_IMETHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
NS_IMETHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn);
NS_IMETHOD CloneNode(nsIDOMNode** aReturn);
NS_IMETHOD Equals(nsIDOMNode* aNode, PRBool aDeep, PRBool* aReturn);
private:
nsString mName;
nsString mValue;
void* mScriptObject;
};
// Another helper class that implements the nsIDOMNamedNodeMap interface.
class DOMAttributeMap : public nsIDOMNamedNodeMap,
public nsIScriptObjectOwner
{
public:
DOMAttributeMap(nsIHTMLContent &aContent);
virtual ~DOMAttributeMap();
NS_DECL_ISUPPORTS
NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject);
NS_IMETHOD ResetScriptObject();
// nsIDOMNamedNodeMap interface
NS_IMETHOD GetLength(PRUint32* aSize);
NS_IMETHOD GetNamedItem(const nsString& aName, nsIDOMNode** aReturn);
NS_IMETHOD SetNamedItem(nsIDOMNode* aNode);
NS_IMETHOD RemoveNamedItem(const nsString& aName, nsIDOMNode** aReturn);
NS_IMETHOD Item(PRUint32 aIndex, nsIDOMNode** aReturn);
private:
nsIHTMLContent& mContent;
void* mScriptObject;
};
//----------------------------------------------------------------------
DOMAttribute::DOMAttribute(const nsString& aName, const nsString& aValue)
: mName(aName), mValue(aValue)
{
mRefCnt = 1;
mScriptObject = nsnull;
}
DOMAttribute::~DOMAttribute()
{
}
nsresult
DOMAttribute::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIDOMAttributeIID)) {
nsIDOMAttribute* tmp = this;
*aInstancePtr = (void*)tmp;
AddRef();
return NS_OK;
}
if (aIID.Equals(kIScriptObjectOwnerIID)) {
nsIScriptObjectOwner* tmp = this;
*aInstancePtr = (void*)tmp;
AddRef();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIDOMAttribute* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*)tmp2;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMPL_ADDREF(DOMAttribute)
NS_IMPL_RELEASE(DOMAttribute)
nsresult
DOMAttribute::GetScriptObject(nsIScriptContext *aContext,
void** aScriptObject)
{
nsresult res = NS_OK;
if (nsnull == mScriptObject) {
res = NS_NewScriptAttribute(aContext, this, nsnull,
(void **)&mScriptObject);
}
*aScriptObject = mScriptObject;
return res;
}
nsresult
DOMAttribute::ResetScriptObject()
{
mScriptObject = nsnull;
return NS_OK;
}
nsresult
DOMAttribute::GetName(nsString& aName)
{
aName = mName;
return NS_OK;
}
nsresult
DOMAttribute::GetValue(nsString& aValue)
{
aValue = mValue;
return NS_OK;
}
nsresult
DOMAttribute::GetSpecified(PRBool* aSpecified)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
DOMAttribute::SetSpecified(PRBool specified)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
DOMAttribute::GetNodeName(nsString& aNodeName)
{
return GetName(aNodeName);
}
NS_IMETHODIMP
DOMAttribute::GetNodeValue(nsString& aNodeValue)
{
return GetValue(aNodeValue);
}
NS_IMETHODIMP
DOMAttribute::SetNodeValue(const nsString& aNodeValue)
{
// You can't actually do this, but we'll fail silently
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetNodeType(PRInt32* aNodeType)
{
*aNodeType = (PRInt32)nsIDOMNode::ATTRIBUTE;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetParentNode(nsIDOMNode** aParentNode)
{
*aParentNode = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetChildNodes(nsIDOMNodeList** aChildNodes)
{
*aChildNodes = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetHasChildNodes(PRBool* aHasChildNodes)
{
*aHasChildNodes = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetFirstChild(nsIDOMNode** aFirstChild)
{
*aFirstChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetLastChild(nsIDOMNode** aLastChild)
{
*aLastChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
{
*aPreviousSibling = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetNextSibling(nsIDOMNode** aNextSibling)
{
*aNextSibling = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
{
*aAttributes = nsnull;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
DOMAttribute::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
DOMAttribute::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
DOMAttribute::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
DOMAttribute::CloneNode(nsIDOMNode** aReturn)
{
DOMAttribute* newAttr = new DOMAttribute(mName, mValue);
if (nsnull == newAttr) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aReturn = newAttr;
return NS_OK;
}
NS_IMETHODIMP
DOMAttribute::Equals(nsIDOMNode* aNode, PRBool aDeep, PRBool* aReturn)
{
// XXX TBI
return NS_OK;
}
//----------------------------------------------------------------------
DOMAttributeMap::DOMAttributeMap(nsIHTMLContent& aContent)
: mContent(aContent)
{
mRefCnt = 1;
mContent.AddRef();
mScriptObject = nsnull;
}
DOMAttributeMap::~DOMAttributeMap()
{
mContent.Release();
}
nsresult
DOMAttributeMap::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIDOMNamedNodeMapIID)) {
nsIDOMNamedNodeMap* tmp = this;
*aInstancePtr = (void*)tmp;
AddRef();
return NS_OK;
}
if (aIID.Equals(kIScriptObjectOwnerIID)) {
nsIScriptObjectOwner* tmp = this;
*aInstancePtr = (void*)tmp;
AddRef();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIDOMNamedNodeMap* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*)tmp2;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMPL_ADDREF(DOMAttributeMap)
NS_IMPL_RELEASE(DOMAttributeMap)
nsresult
DOMAttributeMap::GetScriptObject(nsIScriptContext *aContext,
void** aScriptObject)
{
nsresult res = NS_OK;
if (nsnull == mScriptObject) {
res = NS_NewScriptNamedNodeMap(aContext, this, nsnull,
(void**)&mScriptObject);
}
*aScriptObject = mScriptObject;
return res;
}
nsresult
DOMAttributeMap::ResetScriptObject()
{
mScriptObject = nsnull;
return NS_OK;
}
nsresult
DOMAttributeMap::GetNamedItem(const nsString &aAttrName,
nsIDOMNode** aAttribute)
{
nsAutoString value;
mContent.GetAttribute(aAttrName, value);
*aAttribute = (nsIDOMNode *) new DOMAttribute(aAttrName, value);
return NS_OK;
}
nsresult
DOMAttributeMap::SetNamedItem(nsIDOMNode *aNode)
{
nsIDOMAttribute *attribute;
nsAutoString name, value;
nsresult err;
if (NS_OK != (err = aNode->QueryInterface(kIDOMAttributeIID,
(void **)&attribute))) {
return err;
}
attribute->GetName(name);
attribute->GetValue(value);
NS_RELEASE(attribute);
mContent.SetAttribute(name, value, PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
DOMAttributeMap::RemoveNamedItem(const nsString& aName, nsIDOMNode** aReturn)
{
nsresult res = GetNamedItem(aName, aReturn);
if (NS_OK == res) {
nsAutoString upper;
aName.ToUpperCase(upper);
nsIAtom* attr = NS_NewAtom(upper);
mContent.UnsetAttribute(attr);
}
return res;
}
nsresult
DOMAttributeMap::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
nsresult res = NS_ERROR_FAILURE;
nsAutoString name, value;
nsISupportsArray *attributes = nsnull;
if (NS_OK == NS_NewISupportsArray(&attributes)) {
PRInt32 count;
mContent.GetAllAttributeNames(attributes, count);
if (count > 0) {
if ((PRInt32)aIndex < count) {
nsISupports *att = attributes->ElementAt(aIndex);
static NS_DEFINE_IID(kIAtom, NS_IATOM_IID);
nsIAtom *atName = nsnull;
if (nsnull != att && NS_OK == att->QueryInterface(kIAtom, (void**)&atName)) {
atName->ToString(name);
if (NS_CONTENT_ATTR_NOT_THERE != mContent.GetAttribute(name, value)) {
*aReturn = (nsIDOMNode *)new DOMAttribute(name, value);
res = NS_OK;
}
NS_RELEASE(atName);
}
}
}
NS_RELEASE(attributes);
}
return res;
}
nsresult
DOMAttributeMap::GetLength(PRUint32 *aLength)
{
PRInt32 n;
nsresult rv = mContent.GetAttributeCount(n);
*aLength = PRUint32(n);
return rv;
}
//----------------------------------------------------------------------
static nsresult EnsureWritableAttributes(nsIHTMLAttributes*& aAttributes, PRBool aCreate)
{
nsresult result = NS_OK;
if (nsnull == aAttributes) {
if (PR_TRUE == aCreate) {
result = NS_NewHTMLAttributes(&aAttributes);
if (NS_OK == result) {
aAttributes->AddContentRef();
}
}
}
else {
PRInt32 contentRefCount;
aAttributes->GetContentRefCount(contentRefCount);
if (1 < contentRefCount) {
nsIHTMLAttributes* attrs;
result = aAttributes->Clone(&attrs);
if (NS_OK == result) {
aAttributes->ReleaseContentRef();
NS_RELEASE(aAttributes);
aAttributes = attrs;
aAttributes->AddContentRef();
}
}
}
return result;
}
static void ReleaseAttributes(nsIHTMLAttributes*& aAttributes)
{
aAttributes->ReleaseContentRef();
NS_RELEASE(aAttributes);
}
nsHTMLGenericContent::nsHTMLGenericContent()
{
mDocument = nsnull;
mParent = nsnull;
mAttributes = nsnull;
mTag = nsnull;
mContent = nsnull;
mScriptObject = nsnull;
mListenerManager = nsnull;
}
nsHTMLGenericContent::~nsHTMLGenericContent()
{
if (nsnull != mAttributes) {
ReleaseAttributes(mAttributes);
}
NS_IF_RELEASE(mTag);
NS_IF_RELEASE(mListenerManager);
// XXX what about mScriptObject? it's now safe to GC it...
}
void
nsHTMLGenericContent::Init(nsIHTMLContent* aOuterContentObject,
nsIAtom* aTag)
{
NS_ASSERTION((nsnull == mContent) && (nsnull != aOuterContentObject),
"null ptr");
mContent = aOuterContentObject;
mTag = aTag;
NS_IF_ADDREF(aTag);
}
nsresult
nsHTMLGenericContent::GetNodeName(nsString& aNodeName)
{
return GetTagName(aNodeName);
}
nsresult
nsHTMLGenericContent::GetNodeValue(nsString& aNodeValue)
{
aNodeValue.Truncate();
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetNodeValue(const nsString& aNodeValue)
{
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetNodeType(PRInt32* aNodeType)
{
*aNodeType = nsIDOMNode::ELEMENT;
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetParentNode(nsIDOMNode** aParentNode)
{
if (nsnull != mParent) {
nsresult res = mParent->QueryInterface(kIDOMNodeIID, (void**)aParentNode);
NS_ASSERTION(NS_OK == res, "Must be a DOM Node");
return res;
}
else {
*aParentNode = nsnull;
}
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetPreviousSibling(nsIDOMNode** aNode)
{
if (nsnull != mParent) {
PRInt32 pos;
mParent->IndexOf(mContent, pos);
if (pos > -1) {
nsIContent* prev;
mParent->ChildAt(--pos, prev);
if (nsnull != prev) {
nsresult res = prev->QueryInterface(kIDOMNodeIID, (void**)aNode);
NS_ASSERTION(NS_OK == res, "Must be a DOM Node");
NS_RELEASE(prev); // balance the AddRef in ChildAt()
return res;
}
}
}
*aNode = nsnull;
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetNextSibling(nsIDOMNode** aNextSibling)
{
if (nsnull != mParent) {
PRInt32 pos;
mParent->IndexOf(mContent, pos);
if (pos > -1 ) {
nsIContent* prev;
mParent->ChildAt(++pos, prev);
if (nsnull != prev) {
nsresult res = prev->QueryInterface(kIDOMNodeIID,(void**)aNextSibling);
NS_ASSERTION(NS_OK == res, "Must be a DOM Node");
NS_RELEASE(prev); // balance the AddRef in ChildAt()
return res;
}
}
}
*aNextSibling = nsnull;
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
{
NS_PRECONDITION(nsnull != aAttributes, "null pointer argument");
if (nsnull != mAttributes) {
// XXX Should we create a new one every time or should we
// cache one after we create it? If we find that this is
// something that's called often, we might need to do the
// latter.
*aAttributes = new DOMAttributeMap(*mContent);
}
else {
*aAttributes = nsnull;
}
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetTagName(nsString& aTagName)
{
aTagName.Truncate();
if (nsnull != mTag) {
mTag->ToString(aTagName);
}
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetDOMAttribute(const nsString& aName, nsString& aReturn)
{
GetAttribute(aName, aReturn);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetDOMAttribute(const nsString& aName,
const nsString& aValue)
{
SetAttribute(aName, aValue, PR_TRUE);
return NS_OK;
}
nsresult
nsHTMLGenericContent::RemoveAttribute(const nsString& aName)
{
nsAutoString upper;
aName.ToUpperCase(upper);
nsIAtom* attr = NS_NewAtom(upper);
UnsetAttribute(attr);
NS_RELEASE(attr);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetAttributeNode(const nsString& aName,
nsIDOMAttribute** aReturn)
{
nsAutoString value;
if (NS_CONTENT_ATTR_NOT_THERE != GetAttribute(aName, value)) {
*aReturn = new DOMAttribute(aName, value);
}
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetAttributeNode(nsIDOMAttribute* aAttribute)
{
NS_PRECONDITION(nsnull != aAttribute, "null attribute");
nsresult res = NS_ERROR_FAILURE;
if (nsnull != aAttribute) {
nsAutoString name, value;
res = aAttribute->GetName(name);
if (NS_OK == res) {
res = aAttribute->GetValue(value);
if (NS_OK == res) {
SetAttribute(name, value, PR_TRUE);
}
}
}
return res;
}
nsresult
nsHTMLGenericContent::RemoveAttributeNode(nsIDOMAttribute* aAttribute)
{
NS_PRECONDITION(nsnull != aAttribute, "null attribute");
nsresult res = NS_ERROR_FAILURE;
if (nsnull != aAttribute) {
nsAutoString name;
res = aAttribute->GetName(name);
if (NS_OK == res) {
nsAutoString upper;
name.ToUpperCase(upper);
nsIAtom* attr = NS_NewAtom(upper);
UnsetAttribute(attr);
}
}
return res;
}
nsresult
nsHTMLGenericContent::GetElementsByTagName(const nsString& aTagname,
nsIDOMNodeList** aReturn)
{
return NS_ERROR_NOT_IMPLEMENTED;/* XXX */
}
nsresult
nsHTMLGenericContent::Normalize()
{
return NS_ERROR_NOT_IMPLEMENTED;/* XXX */
}
nsresult
nsHTMLGenericContent::GetId(nsString& aId)
{
GetAttribute(nsHTMLAtoms::id, aId);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetId(const nsString& aId)
{
SetAttr(nsHTMLAtoms::id, aId, eSetAttrNotify_Restart);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetTitle(nsString& aTitle)
{
GetAttribute(nsHTMLAtoms::title, aTitle);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetTitle(const nsString& aTitle)
{
SetAttr(nsHTMLAtoms::title, aTitle, eSetAttrNotify_None);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetLang(nsString& aLang)
{
GetAttribute(nsHTMLAtoms::lang, aLang);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetLang(const nsString& aLang)
{
SetAttr(nsHTMLAtoms::lang, aLang, eSetAttrNotify_Reflow);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetDir(nsString& aDir)
{
GetAttribute(nsHTMLAtoms::dir, aDir);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetDir(const nsString& aDir)
{
SetAttr(nsHTMLAtoms::dir, aDir, eSetAttrNotify_Reflow);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetClassName(nsString& aClassName)
{
GetAttribute(nsHTMLAtoms::kClass, aClassName);
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetClassName(const nsString& aClassName)
{
SetAttr(nsHTMLAtoms::kClass, aClassName, eSetAttrNotify_Restart);
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetDocument(nsIDocument*& aResult) const
{
aResult = mDocument;
NS_IF_ADDREF(mDocument);
return NS_OK;
}
static nsIHTMLStyleSheet* GetAttrStyleSheet(nsIDocument* aDocument)
{
nsIHTMLStyleSheet* sheet = nsnull;
nsIHTMLDocument* htmlDoc;
if (nsnull != aDocument) {
if (NS_OK == aDocument->QueryInterface(kIHTMLDocumentIID, (void**)&htmlDoc)) {
htmlDoc->GetAttributeStyleSheet(&sheet);
}
}
NS_ASSERTION(nsnull != sheet, "can't get attribute style sheet");
return sheet;
}
nsresult
nsHTMLGenericContent::SetDocument(nsIDocument* aDocument)
{
mDocument = aDocument;
// Once the element is added to the doc tree we need to check if
// event handler were registered on it. Unfortunately, this means
// doing a GetAttribute for every type of handler.
if (nsnull != mAttributes) {
nsHTMLValue val;
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onclick, val))
AddScriptEventListener(nsHTMLAtoms::onclick, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::ondblclick, val))
AddScriptEventListener(nsHTMLAtoms::onclick, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmousedown, val))
AddScriptEventListener(nsHTMLAtoms::onmousedown, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseup, val))
AddScriptEventListener(nsHTMLAtoms::onmouseup, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseover, val))
AddScriptEventListener(nsHTMLAtoms::onmouseover, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseout, val))
AddScriptEventListener(nsHTMLAtoms::onmouseout, val, kIDOMMouseListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeydown, val))
AddScriptEventListener(nsHTMLAtoms::onkeydown, val, kIDOMKeyListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeyup, val))
AddScriptEventListener(nsHTMLAtoms::onkeyup, val, kIDOMKeyListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeypress, val))
AddScriptEventListener(nsHTMLAtoms::onkeypress, val, kIDOMKeyListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmousemove, val))
AddScriptEventListener(nsHTMLAtoms::onmousemove, val, kIDOMMouseMotionListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onload, val))
AddScriptEventListener(nsHTMLAtoms::onload, val, kIDOMLoadListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onunload, val))
AddScriptEventListener(nsHTMLAtoms::onunload, val, kIDOMLoadListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onabort, val))
AddScriptEventListener(nsHTMLAtoms::onabort, val, kIDOMLoadListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onerror, val))
AddScriptEventListener(nsHTMLAtoms::onerror, val, kIDOMLoadListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onfocus, val))
AddScriptEventListener(nsHTMLAtoms::onfocus, val, kIDOMFocusListenerIID);
if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onblur, val))
AddScriptEventListener(nsHTMLAtoms::onblur, val, kIDOMFocusListenerIID);
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
sheet->SetAttributesFor(mTag, mAttributes); // sync attributes with sheet
}
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetParent(nsIContent*& aResult) const
{
NS_IF_ADDREF(mParent);
aResult = mParent;
return NS_OK;;
}
nsresult
nsHTMLGenericContent::SetParent(nsIContent* aParent)
{
mParent = aParent;
return NS_OK;
}
nsresult
nsHTMLGenericContent::IsSynthetic(PRBool& aResult)
{
return PR_FALSE;
}
nsresult
nsHTMLGenericContent::GetTag(nsIAtom*& aResult) const
{
NS_IF_ADDREF(mTag);
aResult = mTag;
return NS_OK;
}
//void
//nsHTMLTagContent::SizeOfWithoutThis(nsISizeOfHandler* aHandler) const
//{
// if (!aHandler->HaveSeen(mTag)) {
// mTag->SizeOf(aHandler);
// }
// if (!aHandler->HaveSeen(mAttributes)) {
// mAttributes->SizeOf(aHandler);
// }
//}
nsresult
nsHTMLGenericContent::HandleDOMEvent(nsIPresContext& aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus& aEventStatus)
{
nsresult ret = NS_OK;
nsIDOMEvent* domEvent = nsnull;
if (DOM_EVENT_INIT == aFlags) {
nsIEventStateManager *manager;
if (NS_OK == aPresContext.GetEventStateManager(&manager)) {
manager->SetEventTarget(mContent);
NS_RELEASE(manager);
}
aDOMEvent = &domEvent;
}
//Capturing stage
//Local handling stage
if (nsnull != mListenerManager) {
mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aEventStatus);
}
//Bubbling stage
if (DOM_EVENT_CAPTURE != aFlags && mParent != nsnull) {
ret = mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
DOM_EVENT_BUBBLE, aEventStatus);
}
if (DOM_EVENT_INIT == aFlags) {
// We're leaving the DOM event loop so if we created a DOM event,
// release here.
if (nsnull != *aDOMEvent) {
if (0 != (*aDOMEvent)->Release()) {
// Okay, so someone in the DOM loop (a listener, JS object)
// still has a ref to the DOM Event but the internal data
// hasn't been malloc'd. Force a copy of the data here so the
// DOM Event is still valid.
nsIPrivateDOMEvent *privateEvent;
if (NS_OK == (*aDOMEvent)->QueryInterface(kIPrivateDOMEventIID, (void**)&privateEvent)) {
privateEvent->DuplicatePrivateData();
NS_RELEASE(privateEvent);
}
}
}
aDOMEvent = nsnull;
}
return ret;
}
nsresult
nsHTMLGenericContent::SetAttribute(const nsString& aName,
const nsString& aValue,
PRBool aNotify)
{
nsAutoString upper;
aName.ToUpperCase(upper);
nsIAtom* attr = NS_NewAtom(upper);
nsresult rv = SetAttribute(attr, aValue, aNotify);
NS_RELEASE(attr);
return rv;
}
nsresult
nsHTMLGenericContent::SetAttribute(nsIAtom* aAttribute,
const nsString& aValue,
PRBool aNotify)
{
nsresult result = NS_OK;
if (nsHTMLAtoms::style == aAttribute) {
// XXX the style sheet language is a document property that
// should be used to lookup the style sheet parser to parse the
// attribute.
nsICSSParser* css;
result = NS_NewCSSParser(&css);
if (NS_OK != result) {
return result;
}
nsIStyleRule* rule;
result = css->ParseDeclarations(aValue, nsnull, rule);
if ((NS_OK == result) && (nsnull != rule)) {
result = SetAttribute(aAttribute, nsHTMLValue(rule), aNotify);
NS_RELEASE(rule);
}
NS_RELEASE(css);
}
else {
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
result = sheet->SetAttributeFor(aAttribute, aValue, mTag, mAttributes);
}
else { // manage this ourselves and re-sync when we connect to doc
result = EnsureWritableAttributes(mAttributes, PR_TRUE);
if (nsnull != mAttributes) {
PRInt32 count;
result = mAttributes->SetAttribute(aAttribute, aValue, count);
if (0 == count) {
ReleaseAttributes(mAttributes);
}
}
}
}
return result;
}
nsresult
nsHTMLGenericContent::SetAttribute(nsIAtom* aAttribute,
const nsHTMLValue& aValue,
PRBool aNotify)
{
nsresult result = NS_OK;
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
result = sheet->SetAttributeFor(aAttribute, aValue, mTag, mAttributes);
}
else { // manage this ourselves and re-sync when we connect to doc
result = EnsureWritableAttributes(mAttributes, PR_TRUE);
if (nsnull != mAttributes) {
PRInt32 count;
result = mAttributes->SetAttribute(aAttribute, aValue, count);
if (0 == count) {
ReleaseAttributes(mAttributes);
}
}
}
return result;
}
nsresult
nsHTMLGenericContent::SetAttr(nsIAtom* aAttribute,
const nsString& aValue,
nsSetAttrNotify aNotify)
{
// XXX cheesy code for now
return SetAttribute(aAttribute, aValue, PR_TRUE);
}
nsresult
nsHTMLGenericContent::SetAttr(nsIAtom* aAttribute,
const nsHTMLValue& aValue,
nsSetAttrNotify aNotify)
{
// XXX cheesy code for now
return SetAttribute(aAttribute, aValue, PR_TRUE);
}
nsresult
nsHTMLGenericContent::UnsetAttribute(nsIAtom* aAttribute)
{
nsresult result = NS_OK;
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
result = sheet->UnsetAttributeFor(aAttribute, mTag, mAttributes);
}
else { // manage this ourselves and re-sync when we connect to doc
result = EnsureWritableAttributes(mAttributes, PR_FALSE);
if (nsnull != mAttributes) {
PRInt32 count;
result = mAttributes->UnsetAttribute(aAttribute, count);
if (0 == count) {
ReleaseAttributes(mAttributes);
}
}
}
return result;
}
nsresult
nsHTMLGenericContent::GetAttribute(const nsString& aName,
nsString& aResult) const
{
nsAutoString upper;
aName.ToUpperCase(upper);
nsIAtom* attr = NS_NewAtom(upper);
nsresult result = GetAttribute(attr, aResult);
NS_RELEASE(attr);
return result;
}
nsresult
nsHTMLGenericContent::GetAttribute(nsIAtom *aAttribute,
nsString &aResult) const
{
nsHTMLValue value;
nsresult result = GetAttribute(aAttribute, value);
char cbuf[20];
nscolor color;
if (NS_CONTENT_ATTR_HAS_VALUE == result) {
// Try subclass conversion routine first
if (NS_CONTENT_ATTR_HAS_VALUE ==
mContent->AttributeToString(aAttribute, value, aResult)) {
return result;
}
// Provide default conversions for most everything
switch (value.GetUnit()) {
case eHTMLUnit_Empty:
aResult.Truncate();
break;
case eHTMLUnit_String:
case eHTMLUnit_Null:
value.GetStringValue(aResult);
break;
case eHTMLUnit_Integer:
aResult.Truncate();
aResult.Append(value.GetIntValue(), 10);
break;
case eHTMLUnit_Pixel:
aResult.Truncate();
aResult.Append(value.GetPixelValue(), 10);
break;
case eHTMLUnit_Percent:
aResult.Truncate(0);
aResult.Append(PRInt32(value.GetPercentValue() * 100.0f), 10);
aResult.Append('%');
break;
case eHTMLUnit_Color:
color = nscolor(value.GetColorValue());
PR_snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x",
NS_GET_R(color), NS_GET_G(color), NS_GET_B(color));
aResult.Truncate(0);
aResult.Append(cbuf);
break;
default:
case eHTMLUnit_Enumerated:
NS_NOTREACHED("no default enumerated value to string conversion");
result = NS_CONTENT_ATTR_NOT_THERE;
break;
}
}
return result;
}
nsresult
nsHTMLGenericContent::GetAttribute(nsIAtom* aAttribute,
nsHTMLValue& aValue) const
{
if (nsnull != mAttributes) {
return mAttributes->GetAttribute(aAttribute, aValue);
}
aValue.Reset();
return NS_CONTENT_ATTR_NOT_THERE;
}
nsresult
nsHTMLGenericContent::GetAllAttributeNames(nsISupportsArray* aArray,
PRInt32& aCount) const
{
if (nsnull != mAttributes) {
return mAttributes->GetAllAttributeNames(aArray, aCount);
}
aCount = 0;
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetAttributeCount(PRInt32& aCount) const
{
if (nsnull != mAttributes) {
return mAttributes->Count(aCount);
}
aCount = 0;
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetID(nsIAtom* aID)
{
nsresult result = NS_OK;
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
result = sheet->SetIDFor(aID, mTag, mAttributes);
}
else { // manage this ourselves and re-sync when we connect to doc
EnsureWritableAttributes(mAttributes, PRBool(nsnull != aID));
if (nsnull != mAttributes) {
PRInt32 count;
result = mAttributes->SetID(aID, count);
if (0 == count) {
ReleaseAttributes(mAttributes);
}
}
}
return result;
}
nsresult
nsHTMLGenericContent::GetID(nsIAtom*& aResult) const
{
if (nsnull != mAttributes) {
return mAttributes->GetID(aResult);
}
aResult = nsnull;
return NS_OK;
}
nsresult
nsHTMLGenericContent::SetClass(nsIAtom* aClass)
{
nsresult result = NS_OK;
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
result = sheet->SetClassFor(aClass, mTag, mAttributes);
}
else { // manage this ourselves and re-sync when we connect to doc
EnsureWritableAttributes(mAttributes, PRBool(nsnull != aClass));
if (nsnull != mAttributes) {
PRInt32 count;
result = mAttributes->SetClass(aClass, count);
if (0 == count) {
ReleaseAttributes(mAttributes);
}
}
}
return result;
}
nsresult
nsHTMLGenericContent::GetClass(nsIAtom*& aResult) const
{
if (nsnull != mAttributes) {
return mAttributes->GetClass(aResult);
}
aResult = nsnull;
return NS_OK;
}
nsresult
nsHTMLGenericContent::GetStyleRule(nsIStyleRule*& aResult)
{
nsIStyleRule* result = nsnull;
if (nsnull != mAttributes) {
mAttributes->QueryInterface(kIStyleRuleIID, (void**)&result);
}
aResult = result;
return NS_OK;
}
void
nsHTMLGenericContent::ListAttributes(FILE* out) const
{
nsISupportsArray* attrs;
if (NS_OK == NS_NewISupportsArray(&attrs)) {
PRInt32 index, count;
GetAllAttributeNames(attrs, count);
for (index = 0; index < count; index++) {
// name
nsIAtom* attr = (nsIAtom*)attrs->ElementAt(index);
nsAutoString buffer;
attr->ToString(buffer);
// value
nsAutoString value;
GetAttribute(buffer, value);
buffer.Append("=");
buffer.Append(value);
fputs(" ", out);
fputs(buffer, out);
NS_RELEASE(attr);
}
NS_RELEASE(attrs);
}
}
nsresult
nsHTMLGenericContent::List(FILE* out, PRInt32 aIndent) const
{
NS_PRECONDITION(nsnull != mDocument, "bad content");
PRInt32 index;
for (index = aIndent; --index >= 0; ) fputs(" ", out);
nsIAtom* tag;
GetTag(tag);
if (tag != nsnull) {
nsAutoString buf;
tag->ToString(buf);
fputs(buf, out);
NS_RELEASE(tag);
}
ListAttributes(out);
nsrefcnt r = mContent->AddRef() - 1;
mContent->Release();
fprintf(out, " refcount=%d<", r);
PRBool canHaveKids;
mContent->CanContainChildren(canHaveKids);
if (canHaveKids) {
fputs("\n", out);
PRInt32 kids;
mContent->ChildCount(kids);
for (index = 0; index < kids; index++) {
nsIContent* kid;
mContent->ChildAt(index, kid);
kid->List(out, aIndent + 1);
NS_RELEASE(kid);
}
for (index = aIndent; --index >= 0; ) fputs(" ", out);
}
fputs(">\n", out);
return NS_OK;
}
nsresult
nsHTMLGenericContent::ToHTML(FILE* out) const
{
nsAutoString tmp;
nsresult rv = ToHTMLString(tmp);
fputs(tmp, out);
return rv;
}
// XXX i18n: this is wrong (?) because we need to know the outgoing
// character set (I think)
static void
QuoteForHTML(const nsString& aValue, nsString& aResult)
{
aResult.Truncate();
const PRUnichar* cp = aValue.GetUnicode();
const PRUnichar* end = aValue.GetUnicode() + aValue.Length();
aResult.Append('"');
while (cp < end) {
PRUnichar ch = *cp++;
if ((ch >= 0x20) && (ch <= 0x7f)) {
if (ch == '\"') {
aResult.Append("&quot;");
}
else {
aResult.Append(ch);
}
}
else {
aResult.Append("&#");
aResult.Append((PRInt32) ch, 10);
aResult.Append(';');
}
}
aResult.Append('"');
}
nsresult
nsHTMLGenericContent::ToHTMLString(nsString& aBuf) const
{
aBuf.Truncate(0);
aBuf.Append('<');
if (nsnull != mTag) {
nsAutoString tmp;
mTag->ToString(tmp);
aBuf.Append(tmp);
} else {
aBuf.Append("?NULL");
}
if (nsnull != mAttributes) {
nsISupportsArray* attrs;
nsresult rv = NS_NewISupportsArray(&attrs);
if (NS_OK == rv) {
PRInt32 i, n;
mAttributes->GetAllAttributeNames(attrs, n);
nsAutoString name, value, quotedValue;
for (i = 0; i < n; i++) {
nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i);
atom->ToString(name);
aBuf.Append(' ');
aBuf.Append(name);
value.Truncate();
GetAttribute(name, value);
if (value.Length() > 0) {
aBuf.Append('=');
QuoteForHTML(value, quotedValue);
aBuf.Append(quotedValue);
}
}
NS_RELEASE(attrs);
}
}
aBuf.Append('>');
return NS_OK;
}
//----------------------------------------------------------------------
// nsIScriptObjectOwner implementation
nsresult
nsHTMLGenericContent::GetScriptObject(nsIScriptContext* aContext,
void** aScriptObject)
{
nsresult res = NS_OK;
if (nsnull == mScriptObject) {
nsIDOMElement* ele = nsnull;
mContent->QueryInterface(kIDOMElementIID, (void**) &ele);
res = NS_NewScriptElement(aContext, ele, mParent, (void**)&mScriptObject);
NS_RELEASE(ele);
}
*aScriptObject = mScriptObject;
return res;
}
nsresult
nsHTMLGenericContent::ResetScriptObject()
{
mScriptObject = nsnull;
return NS_OK;
}
//----------------------------------------------------------------------
// nsIDOMEventReceiver implementation
nsresult
nsHTMLGenericContent::GetListenerManager(nsIEventListenerManager** aResult)
{
if (nsnull != mListenerManager) {
NS_ADDREF(mListenerManager);
*aResult = mListenerManager;
return NS_OK;
}
nsresult rv = NS_NewEventListenerManager(aResult);
if (NS_OK == rv) {
mListenerManager = *aResult;
NS_ADDREF(mListenerManager);
}
return rv;
}
nsresult
nsHTMLGenericContent::GetNewListenerManager(nsIEventListenerManager** aResult)
{
return NS_NewEventListenerManager(aResult);
}
nsresult
nsHTMLGenericContent::AddEventListener(nsIDOMEventListener* aListener,
const nsIID& aIID)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
manager->AddEventListener(aListener, aIID);
NS_RELEASE(manager);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
nsHTMLGenericContent::RemoveEventListener(nsIDOMEventListener* aListener,
const nsIID& aIID)
{
if (nsnull != mListenerManager) {
mListenerManager->RemoveEventListener(aListener, aIID);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
//----------------------------------------------------------------------
nsresult
nsHTMLGenericContent::AddScriptEventListener(nsIAtom* aAttribute,
nsHTMLValue& aValue,
REFNSIID aIID)
{
nsresult ret = NS_OK;
nsIScriptContext* context;
nsIScriptContextOwner* owner;
if (nsnull != mDocument) {
owner = mDocument->GetScriptContextOwner();
if (NS_OK == owner->GetScriptContext(&context)) {
if (nsHTMLAtoms::body == mTag || nsHTMLAtoms::frameset == mTag) {
nsIDOMEventReceiver *receiver;
nsIScriptGlobalObject *global = context->GetGlobalObject();
if (nsnull != global && NS_OK == global->QueryInterface(kIDOMEventReceiverIID, (void**)&receiver)) {
nsIEventListenerManager *manager;
if (NS_OK == receiver->GetListenerManager(&manager)) {
nsIScriptObjectOwner *mObjectOwner;
if (NS_OK == global->QueryInterface(kIScriptObjectOwnerIID, (void**)&mObjectOwner)) {
nsString value;
aValue.GetStringValue(value);
ret = manager->AddScriptEventListener(context, mObjectOwner, aAttribute, value, aIID);
NS_RELEASE(mObjectOwner);
}
NS_RELEASE(manager);
}
NS_RELEASE(receiver);
}
NS_IF_RELEASE(global);
}
else {
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
nsString value;
aValue.GetStringValue(value);
nsIScriptObjectOwner* owner;
if (NS_OK == mContent->QueryInterface(kIScriptObjectOwnerIID,
(void**) &owner)) {
ret = manager->AddScriptEventListener(context, owner,
aAttribute, value, aIID);
NS_RELEASE(owner);
}
NS_RELEASE(manager);
}
}
NS_RELEASE(context);
}
NS_RELEASE(owner);
}
return ret;
}
nsresult
nsHTMLGenericContent::AttributeToString(nsIAtom* aAttribute,
nsHTMLValue& aValue,
nsString& aResult) const
{
if (nsHTMLAtoms::style == aAttribute) {
if (eHTMLUnit_ISupports == aValue.GetUnit()) {
nsIStyleRule* rule = (nsIStyleRule*) aValue.GetISupportsValue();
// rule->ToString(str);
aResult = "XXX style rule ToString goes here";
return NS_CONTENT_ATTR_HAS_VALUE;
}
}
aResult.Truncate();
return NS_CONTENT_ATTR_NOT_THERE;
}
PRBool
nsHTMLGenericContent::ParseEnumValue(const nsString& aValue,
EnumTable* aTable,
nsHTMLValue& aResult)
{
while (nsnull != aTable->tag) {
if (aValue.EqualsIgnoreCase(aTable->tag)) {
aResult.SetIntValue(aTable->value, eHTMLUnit_Enumerated);
return PR_TRUE;
}
aTable++;
}
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::EnumValueToString(const nsHTMLValue& aValue,
EnumTable* aTable,
nsString& aResult)
{
aResult.Truncate(0);
if (aValue.GetUnit() == eHTMLUnit_Enumerated) {
PRInt32 v = aValue.GetIntValue();
while (nsnull != aTable->tag) {
if (aTable->value == v) {
aResult.Append(aTable->tag);
return PR_TRUE;
}
aTable++;
}
}
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ParseValueOrPercent(const nsString& aString,
nsHTMLValue& aResult,
nsHTMLUnit aValueUnit)
{ // XXX should vave min/max values?
nsAutoString tmp(aString);
tmp.CompressWhitespace(PR_TRUE, PR_TRUE);
PRInt32 ec, val = tmp.ToInteger(&ec);
if (NS_OK == ec) {
if (tmp.Last() == '%') {/* XXX not 100% compatible with ebina's code */
if (val < 0) val = 0;
if (val > 100) val = 100;
aResult.SetPercentValue(float(val)/100.0f);
} else {
if (eHTMLUnit_Pixel == aValueUnit) {
aResult.SetPixelValue(val);
}
else {
aResult.SetIntValue(val, aValueUnit);
}
}
return PR_TRUE;
}
// Illegal values are mapped to empty
aResult.SetEmptyValue();
return PR_FALSE;
}
/* used to parse attribute values that could be either:
* integer (n),
* percent (n%),
* or proportional (n*)
*/
void
nsHTMLGenericContent::ParseValueOrPercentOrProportional(const nsString& aString,
nsHTMLValue& aResult,
nsHTMLUnit aValueUnit)
{ // XXX should have min/max values?
nsAutoString tmp(aString);
tmp.CompressWhitespace(PR_TRUE, PR_TRUE);
PRInt32 ec, val = tmp.ToInteger(&ec);
if (tmp.Last() == '%') {/* XXX not 100% compatible with ebina's code */
if (val < 0) val = 0;
if (val > 100) val = 100;
aResult.SetPercentValue(float(val)/100.0f);
} else if (tmp.Last() == '*') {
if (val < 0) val = 0;
aResult.SetIntValue(val, eHTMLUnit_Proportional); // proportional values are integers
} else {
if (eHTMLUnit_Pixel == aValueUnit) {
aResult.SetPixelValue(val);
}
else {
aResult.SetIntValue(val, aValueUnit);
}
}
}
PRBool
nsHTMLGenericContent::ValueOrPercentToString(const nsHTMLValue& aValue,
nsString& aResult)
{
aResult.Truncate(0);
switch (aValue.GetUnit()) {
case eHTMLUnit_Integer:
aResult.Append(aValue.GetIntValue(), 10);
return PR_TRUE;
case eHTMLUnit_Pixel:
aResult.Append(aValue.GetPixelValue(), 10);
return PR_TRUE;
case eHTMLUnit_Percent:
aResult.Append(PRInt32(aValue.GetPercentValue() * 100.0f), 10);
aResult.Append('%');
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ParseValue(const nsString& aString, PRInt32 aMin,
nsHTMLValue& aResult, nsHTMLUnit aValueUnit)
{
PRInt32 ec, val = aString.ToInteger(&ec);
if (NS_OK == ec) {
if (val < aMin) val = aMin;
if (eHTMLUnit_Pixel == aValueUnit) {
aResult.SetPixelValue(val);
}
else {
aResult.SetIntValue(val, aValueUnit);
}
return PR_TRUE;
}
// Illegal values are mapped to empty
aResult.SetEmptyValue();
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ParseValue(const nsString& aString, PRInt32 aMin,
PRInt32 aMax,
nsHTMLValue& aResult, nsHTMLUnit aValueUnit)
{
PRInt32 ec, val = aString.ToInteger(&ec);
if (NS_OK == ec) {
if (val < aMin) val = aMin;
if (val > aMax) val = aMax;
if (eHTMLUnit_Pixel == aValueUnit) {
aResult.SetPixelValue(val);
}
else {
aResult.SetIntValue(val, aValueUnit);
}
return PR_TRUE;
}
// Illegal values are mapped to empty
aResult.SetEmptyValue();
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ParseColor(const nsString& aString,
nsHTMLValue& aResult)
{
if (aString.Length() > 0) {
nsAutoString colorStr (aString);
colorStr.CompressWhitespace();
char cbuf[40];
colorStr.ToCString(cbuf, sizeof(cbuf));
nscolor color;
if (NS_ColorNameToRGB(cbuf, &color)) {
aResult.SetStringValue(colorStr);
return PR_TRUE;
}
if (NS_HexToRGB(cbuf, &color)) {
aResult.SetColorValue(color);
return PR_TRUE;
}
}
// Illegal values are mapped to empty
aResult.SetEmptyValue();
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ColorToString(const nsHTMLValue& aValue,
nsString& aResult)
{
if (aValue.GetUnit() == eHTMLUnit_Color) {
nscolor v = aValue.GetColorValue();
char buf[10];
PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x",
NS_GET_R(v), NS_GET_G(v), NS_GET_B(v));
aResult.Truncate(0);
aResult.Append(buf);
return PR_TRUE;
}
if (aValue.GetUnit() == eHTMLUnit_String) {
aValue.GetStringValue(aResult);
return PR_TRUE;
}
if (aValue.GetUnit() == eHTMLUnit_Empty) { // was illegal
aResult.Truncate();
return PR_TRUE;
}
return PR_FALSE;
}
// XXX check all mappings against ebina's usage
static nsHTMLGenericContent::EnumTable kAlignTable[] = {
{ "left", NS_STYLE_TEXT_ALIGN_LEFT },
{ "right", NS_STYLE_TEXT_ALIGN_RIGHT },
{ "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
{ "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE },
{ "center", NS_STYLE_TEXT_ALIGN_CENTER },
{ "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
{ "top", NS_STYLE_VERTICAL_ALIGN_TOP },
{ "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
{ "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
{ "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
{ "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
{ 0 }
};
PRBool
nsHTMLGenericContent::ParseAlignValue(const nsString& aString,
nsHTMLValue& aResult)
{
return ParseEnumValue(aString, kAlignTable, aResult);
}
PRBool
nsHTMLGenericContent::AlignValueToString(const nsHTMLValue& aValue,
nsString& aResult)
{
return EnumValueToString(aValue, kAlignTable, aResult);
}
PRBool
nsHTMLGenericContent::ParseImageAttribute(nsIAtom* aAttribute,
const nsString& aString,
nsHTMLValue& aResult)
{
if ((aAttribute == nsHTMLAtoms::width) ||
(aAttribute == nsHTMLAtoms::height)) {
ParseValueOrPercent(aString, aResult, eHTMLUnit_Pixel);
return PR_TRUE;
}
else if ((aAttribute == nsHTMLAtoms::hspace) ||
(aAttribute == nsHTMLAtoms::vspace) ||
(aAttribute == nsHTMLAtoms::border)) {
ParseValue(aString, 0, aResult, eHTMLUnit_Pixel);
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsHTMLGenericContent::ImageAttributeToString(nsIAtom* aAttribute,
const nsHTMLValue& aValue,
nsString& aResult)
{
if ((aAttribute == nsHTMLAtoms::width) ||
(aAttribute == nsHTMLAtoms::height) ||
(aAttribute == nsHTMLAtoms::border) ||
(aAttribute == nsHTMLAtoms::hspace) ||
(aAttribute == nsHTMLAtoms::vspace)) {
return ValueOrPercentToString(aValue, aResult);
}
return PR_FALSE;
}
void
nsHTMLGenericContent::MapImageAttributesInto(nsIStyleContext* aContext,
nsIPresContext* aPresContext)
{
if (nsnull != mAttributes) {
nsHTMLValue value;
float p2t = aPresContext->GetPixelsToTwips();
nsStylePosition* pos = (nsStylePosition*)
aContext->GetMutableStyleData(eStyleStruct_Position);
nsStyleSpacing* spacing = (nsStyleSpacing*)
aContext->GetMutableStyleData(eStyleStruct_Spacing);
// width: value
GetAttribute(nsHTMLAtoms::width, value);
if (value.GetUnit() == eHTMLUnit_Pixel) {
nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
pos->mWidth.SetCoordValue(twips);
}
else if (value.GetUnit() == eHTMLUnit_Percent) {
pos->mWidth.SetPercentValue(value.GetPercentValue());
}
// height: value
GetAttribute(nsHTMLAtoms::height, value);
if (value.GetUnit() == eHTMLUnit_Pixel) {
nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
pos->mHeight.SetCoordValue(twips);
}
else if (value.GetUnit() == eHTMLUnit_Percent) {
pos->mHeight.SetPercentValue(value.GetPercentValue());
}
// hspace: value
GetAttribute(nsHTMLAtoms::hspace, value);
if (value.GetUnit() == eHTMLUnit_Pixel) {
nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
spacing->mMargin.SetRight(nsStyleCoord(twips));
}
else if (value.GetUnit() == eHTMLUnit_Percent) {
spacing->mMargin.SetRight(nsStyleCoord(value.GetPercentValue(),
eStyleUnit_Coord));
}
// vspace: value
GetAttribute(nsHTMLAtoms::vspace, value);
if (value.GetUnit() == eHTMLUnit_Pixel) {
nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
spacing->mMargin.SetBottom(nsStyleCoord(twips));
}
else if (value.GetUnit() == eHTMLUnit_Percent) {
spacing->mMargin.SetBottom(nsStyleCoord(value.GetPercentValue(),
eStyleUnit_Coord));
}
}
}
void
nsHTMLGenericContent::MapImageAlignAttributeInto(nsIStyleContext* aContext,
nsIPresContext* aPresContext)
{
if (nsnull != mAttributes) {
nsHTMLValue value;
GetAttribute(nsHTMLAtoms::align, value);
if (value.GetUnit() == eHTMLUnit_Enumerated) {
PRUint8 align = value.GetIntValue();
nsStyleDisplay* display = (nsStyleDisplay*)
aContext->GetMutableStyleData(eStyleStruct_Display);
nsStyleText* text = (nsStyleText*)
aContext->GetMutableStyleData(eStyleStruct_Text);
nsStyleSpacing* spacing = (nsStyleSpacing*)
aContext->GetMutableStyleData(eStyleStruct_Spacing);
float p2t = aPresContext->GetPixelsToTwips();
nsStyleCoord three(NSIntPixelsToTwips(3, p2t));
switch (align) {
case NS_STYLE_TEXT_ALIGN_LEFT:
display->mFloats = NS_STYLE_FLOAT_LEFT;
spacing->mMargin.SetLeft(three);
spacing->mMargin.SetRight(three);
break;
case NS_STYLE_TEXT_ALIGN_RIGHT:
display->mFloats = NS_STYLE_FLOAT_RIGHT;
spacing->mMargin.SetLeft(three);
spacing->mMargin.SetRight(three);
break;
default:
text->mVerticalAlign.SetIntValue(align, eStyleUnit_Enumerated);
break;
}
}
}
}
void
nsHTMLGenericContent::MapImageBorderAttributesInto(nsIStyleContext* aContext,
nsIPresContext* aPresContext,
nscolor aBorderColors[4])
{
if (nsnull != mAttributes) {
nsHTMLValue value;
// border: pixels
GetAttribute(nsHTMLAtoms::border, value);
if (value.GetUnit() != eHTMLUnit_Pixel) {
if (nsnull == aBorderColors) {
return;
}
// If no border is defined and we are forcing a border, force
// the size to 2 pixels.
value.SetPixelValue(2);
}
float p2t = aPresContext->GetPixelsToTwips();
nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
// Fixup border-padding sums: subtract out the old size and then
// add in the new size.
nsStyleSpacing* spacing = (nsStyleSpacing*)
aContext->GetMutableStyleData(eStyleStruct_Spacing);
nsStyleCoord coord;
coord.SetCoordValue(twips);
spacing->mBorder.SetTop(coord);
spacing->mBorder.SetRight(coord);
spacing->mBorder.SetBottom(coord);
spacing->mBorder.SetLeft(coord);
spacing->mBorderStyle[0] = NS_STYLE_BORDER_STYLE_SOLID;
spacing->mBorderStyle[1] = NS_STYLE_BORDER_STYLE_SOLID;
spacing->mBorderStyle[2] = NS_STYLE_BORDER_STYLE_SOLID;
spacing->mBorderStyle[3] = NS_STYLE_BORDER_STYLE_SOLID;
// Use supplied colors if provided, otherwise use color for border
// color
if (nsnull != aBorderColors) {
spacing->mBorderColor[0] = aBorderColors[0];
spacing->mBorderColor[1] = aBorderColors[1];
spacing->mBorderColor[2] = aBorderColors[2];
spacing->mBorderColor[3] = aBorderColors[3];
}
else {
// Color is inherited from "color"
const nsStyleColor* styleColor = (const nsStyleColor*)
aContext->GetStyleData(eStyleStruct_Color);
nscolor color = styleColor->mColor;
spacing->mBorderColor[0] = color;
spacing->mBorderColor[1] = color;
spacing->mBorderColor[2] = color;
spacing->mBorderColor[3] = color;
}
}
}
void
nsHTMLGenericContent::TriggerLink(nsIPresContext& aPresContext,
const nsString& aBase,
const nsString& aURLSpec,
const nsString& aTargetSpec,
PRBool aClick)
{
nsILinkHandler* handler;
if (NS_OK == aPresContext.GetLinkHandler(&handler) && (nsnull != handler)) {
// Resolve url to an absolute url
nsIURL* docURL = nsnull;
nsIDocument* doc;
if (NS_OK == GetDocument(doc)) {
docURL = doc->GetDocumentURL();
NS_RELEASE(doc);
}
nsAutoString absURLSpec;
if (aURLSpec.Length() > 0) {
nsresult rv = NS_MakeAbsoluteURL(docURL, aBase, aURLSpec, absURLSpec);
}
else {
absURLSpec = aURLSpec;
}
if (nsnull != docURL) {
NS_RELEASE(docURL);
}
// Now pass on absolute url to the click handler
if (aClick) {
handler->OnLinkClick(nsnull, absURLSpec, aTargetSpec);
}
else {
handler->OnOverLink(nsnull, absURLSpec, aTargetSpec);
}
NS_RELEASE(handler);
}
}
//----------------------------------------------------------------------
nsHTMLGenericLeafContent::nsHTMLGenericLeafContent()
{
}
nsHTMLGenericLeafContent::~nsHTMLGenericLeafContent()
{
}
nsresult
nsHTMLGenericLeafContent::CopyInnerTo(nsIHTMLContent* aSrcContent,
nsHTMLGenericLeafContent* aDst)
{
aDst->mContent = aSrcContent;
// XXX should the node's document be set?
// XXX copy attributes not yet impelemented
return NS_OK;
}
nsresult
nsHTMLGenericLeafContent::Equals(nsIDOMNode* aNode, PRBool aDeep,
PRBool* aReturn)
{
// XXX not yet implemented
*aReturn = PR_FALSE;
return NS_OK;
}
nsresult
nsHTMLGenericLeafContent::BeginConvertToXIF(nsXIFConverter& aConverter) const
{
nsresult rv = NS_OK;
if (nsnull != mTag)
{
nsAutoString name;
mTag->ToString(name);
aConverter.BeginLeaf(name);
}
// Add all attributes to the convert
if (nsnull != mAttributes)
{
nsISupportsArray* attrs;
rv = NS_NewISupportsArray(&attrs);
if (NS_OK == rv)
{
PRInt32 i, n;
mAttributes->GetAllAttributeNames(attrs, n);
nsAutoString name, value;
for (i = 0; i < n; i++)
{
nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i);
atom->ToString(name);
value.Truncate();
GetAttribute(name, value);
aConverter.AddHTMLAttribute(name,value);
}
NS_RELEASE(attrs);
}
}
return rv;
}
nsresult
nsHTMLGenericLeafContent::ConvertContentToXIF(nsXIFConverter& aConverter) const
{
return NS_OK;
}
nsresult
nsHTMLGenericLeafContent::FinishConvertToXIF(nsXIFConverter& aConverter) const
{
if (nsnull != mTag)
{
nsAutoString name;
mTag->ToString(name);
aConverter.EndLeaf(name);
}
return NS_OK;
}
// XXX not really implemented (yet)
nsresult
nsHTMLGenericLeafContent::SizeOf(nsISizeOfHandler* aHandler) const
{
aHandler->Add(sizeof(*this));
return NS_OK;
}
//----------------------------------------------------------------------
nsHTMLGenericContainerContent::nsHTMLGenericContainerContent()
{
}
nsHTMLGenericContainerContent::~nsHTMLGenericContainerContent()
{
PRInt32 n = mChildren.Count();
for (PRInt32 i = 0; i < n; i++) {
nsIContent* kid = (nsIContent*) mChildren.ElementAt(i);
NS_RELEASE(kid);
}
// if (nsnull != mChildNodes) {
// mChildNodes->ReleaseContent();
// NS_RELEASE(mChildNodes);
// }
}
nsresult
nsHTMLGenericContainerContent:: CopyInnerTo(nsIHTMLContent* aSrcContent,
nsHTMLGenericContainerContent* aDst)
{
aDst->mContent = aSrcContent;
// XXX should the node's document be set?
// XXX copy attributes not yet impelemented
// XXX deep copy?
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::Equals(nsIDOMNode* aNode, PRBool aDeep,
PRBool* aReturn)
{
// XXX not yet implemented
*aReturn = PR_FALSE;
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::GetChildNodes(nsIDOMNodeList** aChildNodes)
{
*aChildNodes = nsnull;
return NS_OK;
// NS_PRECONDITION(nsnull != aChildNodes, "null pointer");
// if (nsnull == mChildNodes) {
// mChildNodes = new nsDOMNodeList(this);
// NS_ADDREF(mChildNodes);
// }
// *aChildNodes = mChildNodes;
// NS_ADDREF(mChildNodes);
// return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::GetHasChildNodes(PRBool* aReturn)
{
if (0 != mChildren.Count()) {
*aReturn = PR_TRUE;
}
else {
*aReturn = PR_FALSE;
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::GetFirstChild(nsIDOMNode** aNode)
{
nsIContent *child = (nsIContent*) mChildren.ElementAt(0);
if (nsnull != child) {
nsresult res = child->QueryInterface(kIDOMNodeIID, (void**)aNode);
NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); // must be a DOM Node
return res;
}
aNode = nsnull;
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::GetLastChild(nsIDOMNode** aNode)
{
nsIContent *child = (nsIContent*) mChildren.ElementAt(mChildren.Count()-1);
if (nsnull != child) {
nsresult res = child->QueryInterface(kIDOMNodeIID, (void**)aNode);
NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); // must be a DOM Node
return res;
}
aNode = nsnull;
return NS_OK;
}
static void
SetDocumentInChildrenOf(nsIContent* aContent, nsIDocument* aDocument)
{
PRInt32 i, n;
aContent->ChildCount(n);
for (i = 0; i < n; i++) {
nsIContent* child;
aContent->ChildAt(i, child);
if (nsnull != child) {
child->SetDocument(aDocument);
SetDocumentInChildrenOf(child, aDocument);
NS_RELEASE(child);
}
}
}
// XXX It's possible that newChild has already been inserted in the
// tree; if this is the case then we need to remove it from where it
// was before placing it in it's new home
nsresult
nsHTMLGenericContainerContent::InsertBefore(nsIDOMNode* aNewChild,
nsIDOMNode* aRefChild,
nsIDOMNode** aReturn)
{
if (nsnull == aNewChild) {
*aReturn = nsnull;
return NS_OK;/* XXX wrong error value */
}
// Get the nsIContent interface for the new content
nsIContent* newContent = nsnull;
nsresult res = aNewChild->QueryInterface(kIContentIID, (void**)&newContent);
NS_ASSERTION(NS_OK == res, "New child must be an nsIContent");
if (NS_OK == res) {
if (nsnull == aRefChild) {
// Append the new child to the end
SetDocumentInChildrenOf(newContent, mDocument);
res = AppendChildTo(newContent, PR_TRUE);
}
else {
// Get the index of where to insert the new child
nsIContent* refContent = nsnull;
res = aRefChild->QueryInterface(kIContentIID, (void**)&refContent);
NS_ASSERTION(NS_OK == res, "Ref child must be an nsIContent");
if (NS_OK == res) {
PRInt32 pos;
IndexOf(refContent, pos);
if (pos >= 0) {
SetDocumentInChildrenOf(newContent, mDocument);
res = InsertChildAt(newContent, pos, PR_TRUE);
}
NS_RELEASE(refContent);
}
}
NS_RELEASE(newContent);
*aReturn = aNewChild;
NS_ADDREF(aNewChild);
}
else {
*aReturn = nsnull;
}
return res;
}
nsresult
nsHTMLGenericContainerContent::ReplaceChild(nsIDOMNode* aNewChild,
nsIDOMNode* aOldChild,
nsIDOMNode** aReturn)
{
nsIContent* content = nsnull;
*aReturn = nsnull;
nsresult res = aOldChild->QueryInterface(kIContentIID, (void**)&content);
NS_ASSERTION(NS_OK == res, "Must be an nsIContent");
if (NS_OK == res) {
PRInt32 pos;
IndexOf(content, pos);
if (pos >= 0) {
nsIContent* newContent = nsnull;
nsresult res = aNewChild->QueryInterface(kIContentIID, (void**)&newContent);
NS_ASSERTION(NS_OK == res, "Must be an nsIContent");
if (NS_OK == res) {
res = ReplaceChildAt(newContent, pos, PR_TRUE);
NS_RELEASE(newContent);
}
*aReturn = aOldChild;
NS_ADDREF(aOldChild);
}
NS_RELEASE(content);
}
return res;
}
nsresult
nsHTMLGenericContainerContent::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
nsIContent* content = nsnull;
*aReturn = nsnull;
nsresult res = aOldChild->QueryInterface(kIContentIID, (void**)&content);
NS_ASSERTION(NS_OK == res, "Must be an nsIContent");
if (NS_OK == res) {
PRInt32 pos;
IndexOf(content, pos);
if (pos >= 0) {
res = RemoveChildAt(pos, PR_TRUE);
*aReturn = aOldChild;
NS_ADDREF(aOldChild);
}
NS_RELEASE(content);
}
return res;
}
nsresult
nsHTMLGenericContainerContent::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return InsertBefore(aNewChild, nsnull, aReturn);
}
nsresult
nsHTMLGenericContainerContent::SizeOf(nsISizeOfHandler* aHandler) const
{
aHandler->Add(sizeof(*this));
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::BeginConvertToXIF(nsXIFConverter& aConverter) const
{
nsresult rv = NS_OK;
if (nsnull != mTag)
{
nsAutoString name;
mTag->ToString(name);
aConverter.BeginContainer(name);
}
// Add all attributes to the convert
if (nsnull != mAttributes)
{
nsISupportsArray* attrs;
rv = NS_NewISupportsArray(&attrs);
if (NS_OK == rv)
{
PRInt32 i, n;
mAttributes->GetAllAttributeNames(attrs, n);
nsAutoString name, value;
for (i = 0; i < n; i++)
{
nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i);
atom->ToString(name);
value.Truncate();
GetAttribute(name, value);
aConverter.AddHTMLAttribute(name,value);
}
NS_RELEASE(attrs);
}
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::ConvertContentToXIF(nsXIFConverter& aConverter) const
{
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::FinishConvertToXIF(nsXIFConverter& aConverter) const
{
if (nsnull != mTag)
{
nsAutoString name;
mTag->ToString(name);
aConverter.EndContainer(name);
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::Compact()
{
mChildren.Compact();
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::CanContainChildren(PRBool& aResult) const
{
aResult = PR_TRUE;
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::ChildCount(PRInt32& aCount) const
{
aCount = mChildren.Count();
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::ChildAt(PRInt32 aIndex,
nsIContent*& aResult) const
{
nsIContent *child = (nsIContent*) mChildren.ElementAt(aIndex);
if (nsnull != child) {
NS_ADDREF(child);
}
aResult = child;
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::IndexOf(nsIContent* aPossibleChild,
PRInt32& aIndex) const
{
NS_PRECONDITION(nsnull != aPossibleChild, "null ptr");
aIndex = mChildren.IndexOf(aPossibleChild);
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::InsertChildAt(nsIContent* aKid,
PRInt32 aIndex,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc);
if (aNotify) {
doc->ContentInserted(mContent, aKid, aIndex);
}
}
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::ReplaceChildAt(nsIContent* aKid,
PRInt32 aIndex,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex);
PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc);
if (aNotify) {
doc->ContentReplaced(mContent, oldKid, aKid, aIndex);
}
}
oldKid->SetDocument(nsnull);
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr");
PRBool rv = mChildren.AppendElement(aKid);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc);
if (aNotify) {
doc->ContentAppended(mContent, mChildren.Count() - 1);
}
}
}
return NS_OK;
}
nsresult
nsHTMLGenericContainerContent::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
{
nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex);
if (nsnull != oldKid ) {
nsIDocument* doc = mDocument;
if (aNotify) {
if (nsnull != doc) {
doc->ContentWillBeRemoved(mContent, oldKid, aIndex);
}
}
PRBool rv = mChildren.RemoveElementAt(aIndex);
if (aNotify) {
if (nsnull != doc) {
doc->ContentHasBeenRemoved(mContent, oldKid, aIndex);
}
}
oldKid->SetDocument(nsnull);
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
return NS_OK;
}