/* -*- 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.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/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. * * Contributor(s): */ #include "nsIDOMComment.h" #include "nsGenericDOMDataNode.h" #include "nsIDOMEventReceiver.h" #include "nsIContent.h" #include "nsLayoutAtoms.h" #include "nsISelection.h" #include "nsISelectionPrivate.h" #include "nsIDocument.h" #include "nsIEnumerator.h" #include "nsCOMPtr.h" #include "nsIDOMRange.h" #include "nsString.h" #include "nsContentUtils.h" class nsCommentNode : public nsIDOMComment, public nsITextContent { public: nsCommentNode(); virtual ~nsCommentNode(); // nsISupports NS_DECL_ISUPPORTS // nsIDOMNode NS_IMPL_NSIDOMNODE_USING_GENERIC_DOM_DATA(mInner) // nsIDOMCharacterData NS_IMPL_NSIDOMCHARACTERDATA_USING_GENERIC_DOM_DATA(mInner) // nsIDOMComment // nsIContent //NS_IMPL_ICONTENT_USING_GENERIC_DOM_DATA(mInner) NS_IMETHOD GetDocument(nsIDocument*& aResult) const { return mInner.GetDocument(aResult); } NS_IMETHOD SetDocument(nsIDocument* aDocument, PRBool aDeep, PRBool aCompileEventHandlers) { return mInner.SetDocument(aDocument, aDeep, aCompileEventHandlers); } NS_IMETHOD GetParent(nsIContent*& aResult) const { return mInner.GetParent(aResult); } NS_IMETHOD SetParent(nsIContent* aParent) { return mInner.SetParent(aParent); } NS_IMETHOD CanContainChildren(PRBool& aResult) const { return mInner.CanContainChildren(aResult); } NS_IMETHOD ChildCount(PRInt32& aResult) const { return mInner.ChildCount(aResult); } NS_IMETHOD ChildAt(PRInt32 aIndex, nsIContent*& aResult) const { return mInner.ChildAt(aIndex, aResult); } NS_IMETHOD IndexOf(nsIContent* aPossibleChild, PRInt32& aResult) const { return mInner.IndexOf(aPossibleChild, aResult); } NS_IMETHOD InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify, PRBool aDeepSetDocument) { return mInner.InsertChildAt(aKid, aIndex, aNotify, aDeepSetDocument); } NS_IMETHOD ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify, PRBool aDeepSetDocument) { return mInner.ReplaceChildAt(aKid, aIndex, aNotify, aDeepSetDocument); } NS_IMETHOD AppendChildTo(nsIContent* aKid, PRBool aNotify, PRBool aDeepSetDocument) { return mInner.AppendChildTo(aKid, aNotify, aDeepSetDocument); } NS_IMETHOD RemoveChildAt(PRInt32 aIndex, PRBool aNotify) { return mInner.RemoveChildAt(aIndex, aNotify); } NS_IMETHOD GetNameSpaceID(PRInt32& aID) const { return mInner.GetNameSpaceID(aID); } NS_IMETHOD GetTag(nsIAtom*& aResult) const; NS_IMETHOD GetNodeInfo(nsINodeInfo*& aResult) const { aResult = nsnull; return NS_OK; } NS_IMETHOD NormalizeAttributeString(const nsAReadableString& aStr, nsINodeInfo*& aNodeInfo) { aNodeInfo = nsnull; return NS_OK; } NS_IMETHOD GetAttribute(PRInt32 aNameSpaceID, nsIAtom *aAttribute, nsAWritableString& aResult) const { return mInner.GetAttribute(aNameSpaceID, aAttribute, aResult); } NS_IMETHOD GetAttribute(PRInt32 aNameSpaceID, nsIAtom *aAttribute, nsIAtom*& aPrefix, nsAWritableString& aResult) const { return mInner.GetAttribute(aNameSpaceID, aAttribute, aPrefix, aResult); } NS_IMETHOD SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute, const nsAReadableString& aValue, PRBool aNotify) { return mInner.SetAttribute(aNameSpaceID, aAttribute, aValue, aNotify); } NS_IMETHOD SetAttribute(nsINodeInfo* aNodeInfo, const nsAReadableString& aValue, PRBool aNotify) { return mInner.SetAttribute(aNodeInfo, aValue, aNotify); } NS_IMETHOD UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify) { return mInner.UnsetAttribute(aNameSpaceID, aAttribute, aNotify); } NS_IMETHOD GetAttributeNameAt(PRInt32 aIndex, PRInt32& aNameSpaceID, nsIAtom*& aName, nsIAtom*& aPrefix) const { return mInner.GetAttributeNameAt(aIndex, aNameSpaceID, aName, aPrefix); } NS_IMETHOD GetAttributeCount(PRInt32& aResult) const { return mInner.GetAttributeCount(aResult); } NS_IMETHOD List(FILE* out, PRInt32 aIndent) const; NS_IMETHOD DumpContent(FILE* out = stdout, PRInt32 aIndent = 0,PRBool aDumpAll=PR_TRUE) const { return NS_OK; } NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus); NS_IMETHOD GetContentID(PRUint32* aID) { *aID = mContentID; return NS_OK; } NS_IMETHOD SetContentID(PRUint32 aID) { mContentID = aID; return NS_OK; } NS_IMETHOD RangeAdd(nsIDOMRange& aRange){ return mInner.RangeAdd(aRange); } NS_IMETHOD RangeRemove(nsIDOMRange& aRange){ return mInner.RangeRemove(aRange); } NS_IMETHOD GetRangeList(nsVoidArray*& aResult) const { return mInner.GetRangeList(aResult); } NS_IMETHOD SetFocus(nsIPresContext* aContext) { return mInner.SetFocus(aContext); } NS_IMETHOD RemoveFocus(nsIPresContext* aContext) { return mInner.RemoveFocus(aContext); } NS_IMETHOD GetBindingParent(nsIContent** aContent) { return mInner.GetBindingParent(aContent); } NS_IMETHOD SetBindingParent(nsIContent* aParent) { return mInner.SetBindingParent(aParent); } NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags) { return PR_FALSE; } NS_IMETHOD GetListenerManager(nsIEventListenerManager** aResult) { return mInner.GetListenerManager(this, aResult); } NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const { if (!aResult) { return NS_ERROR_NULL_POINTER; } #ifdef DEBUG *aResult = sizeof(*this); #else *aResult = 0; #endif return NS_OK; } NS_IMETHOD GetText(const nsTextFragment** aFragmentsResult) { return mInner.GetText(aFragmentsResult); } NS_IMETHOD GetTextLength(PRInt32* aLengthResult) { return mInner.GetTextLength(aLengthResult); } NS_IMETHOD CopyText(nsAWritableString& aResult) { return mInner.CopyText(aResult); } NS_IMETHOD SetText(const PRUnichar* aBuffer, PRInt32 aLength, PRBool aNotify); NS_IMETHOD SetText(const nsAReadableString& aStr, PRBool aNotify); NS_IMETHOD SetText(const char* aBuffer, PRInt32 aLength, PRBool aNotify); NS_IMETHOD IsOnlyWhitespace(PRBool* aResult) { return mInner.IsOnlyWhitespace(aResult); } NS_IMETHOD CloneContent(PRBool aCloneText, nsITextContent** aClone); protected: nsGenericDOMDataNode mInner; PRUint32 mContentID; }; nsresult NS_NewCommentNode(nsIContent** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } nsIContent* it = new nsCommentNode(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(NS_GET_IID(nsIContent), (void **) aInstancePtrResult); } nsCommentNode::nsCommentNode() { NS_INIT_REFCNT(); mContentID = 0; } nsCommentNode::~nsCommentNode() { } // XPConnect interface list for nsCommentNode NS_CLASSINFO_MAP_BEGIN(Comment) NS_CLASSINFO_MAP_ENTRY(nsIDOMComment) NS_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) NS_CLASSINFO_MAP_ENTRY(nsIDOM3Node) NS_CLASSINFO_MAP_END // QueryInterface implementation for nsCommentNode NS_INTERFACE_MAP_BEGIN(nsCommentNode) NS_INTERFACE_MAP_ENTRY_DOM_DATA() NS_INTERFACE_MAP_ENTRY(nsITextContent) NS_INTERFACE_MAP_ENTRY(nsIDOMComment) NS_INTERFACE_MAP_ENTRY(nsIDOMCharacterData) NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Comment) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsCommentNode) NS_IMPL_RELEASE(nsCommentNode) NS_IMETHODIMP nsCommentNode::GetTag(nsIAtom*& aResult) const { aResult = nsLayoutAtoms::commentTagName; NS_ADDREF(aResult); return NS_OK; } NS_IMETHODIMP nsCommentNode::GetNodeName(nsAWritableString& aNodeName) { aNodeName.Assign(NS_LITERAL_STRING("#comment")); return NS_OK; } NS_IMETHODIMP nsCommentNode::GetNodeType(PRUint16* aNodeType) { *aNodeType = (PRUint16)nsIDOMNode::COMMENT_NODE; return NS_OK; } NS_IMETHODIMP nsCommentNode::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) { nsresult result = NS_OK; nsCommentNode* it = new nsCommentNode(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } // XXX Increment the ref count before calling any // methods. If they do a QI and then a Release() // the instance will be deleted. result = it->QueryInterface(NS_GET_IID(nsIDOMNode), (void**) aReturn); if (NS_FAILED(result)) { return result; } nsAutoString data; result = GetData(data); if (NS_FAILED(result)) { NS_RELEASE(*aReturn); return result; } result = it->SetData(data); if (NS_FAILED(result)) { NS_RELEASE(*aReturn); return result; } return result; } NS_IMETHODIMP nsCommentNode::CloneContent(PRBool aCloneText, nsITextContent** aReturn) { nsresult result = NS_OK; nsCommentNode* it; NS_NEWXPCOM(it, nsCommentNode); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } result = it->QueryInterface(NS_GET_IID(nsITextContent), (void**) aReturn); if (NS_FAILED(result) || !aCloneText) { return result; } nsAutoString data; result = GetData(data); if (NS_FAILED(result)) { NS_RELEASE(*aReturn); return result; } result = it->SetData(data); if (NS_FAILED(result)) { NS_RELEASE(*aReturn); return result; } return result; } NS_IMETHODIMP nsCommentNode::List(FILE* out, PRInt32 aIndent) const { NS_PRECONDITION(nsnull != mInner.mDocument, "bad content"); PRInt32 indx; for (indx = aIndent; --indx >= 0; ) fputs(" ", out); fprintf(out, "Comment@%p refcount=%d\n", out); return NS_OK; } NS_IMETHODIMP nsCommentNode::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { return mInner.HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aFlags, aEventStatus); } // This would ideally be done by the parser, but for the sake // of "genericity" it's being done in the comment content code static void StripCommentDelimiters(nsString& aCommentString) { PRInt32 offset; static char* kCommentStart = ""; static char* kCommentAlternateEnd = "--!>"; static char kMinus = '-'; offset = aCommentString.Find(kCommentStart); if (-1 != offset) { // Take up to 2 '-' characters offset += strlen(kCommentStart); if (kMinus == aCommentString.CharAt(offset)) { offset++; if (kMinus == aCommentString.CharAt(offset)) { offset++; } } aCommentString.Cut(0, offset); } offset = aCommentString.RFind(kCommentEnd); if (offset > 0) { // Take up to 1 more '-' if (kMinus == aCommentString.CharAt(offset-1)) { offset--; } aCommentString.Cut(offset, aCommentString.Length()-offset); } else { offset = aCommentString.RFind(kCommentAlternateEnd); if (-1 != offset) { aCommentString.Cut(offset, aCommentString.Length()-offset); } } } NS_IMETHODIMP nsCommentNode::SetText(const PRUnichar* aBuffer, PRInt32 aLength, PRBool aNotify) { nsAutoString str(aBuffer); StripCommentDelimiters(str); return mInner.SetText(this, str.GetUnicode(), str.Length(), aNotify); } NS_IMETHODIMP nsCommentNode::SetText(const nsAReadableString& aStr, PRBool aNotify) { nsAutoString str(aStr); StripCommentDelimiters(str); return mInner.SetText(this, str.GetUnicode(), str.Length(), aNotify); } NS_IMETHODIMP nsCommentNode::SetText(const char* aBuffer, PRInt32 aLength, PRBool aNotify) { nsAutoString str; str.AssignWithConversion(aBuffer); StripCommentDelimiters(str); return mInner.SetText(this, str.GetUnicode(), str.Length(), aNotify); }