Files
Mozilla/mozilla/layout/html/content/src/nsAttributeContent.cpp
jst%netscape.com 17e33bbc26 Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).

Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst


git-svn-id: svn://10.0.0.236/trunk@80681 18797224-902f-48f8-a5cc-f745e15eee43
2000-10-07 10:57:30 +00:00

571 lines
15 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.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):
* Pierre Phaneuf <pp@ludusdesign.com>
*/
#include "nsIAttributeContent.h"
#include "nsGenericElement.h"
#include "nsIDocument.h"
#include "nsIEventListenerManager.h"
#include "nsIDocument.h"
#include "nsIDOMRange.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentFragment.h"
#include "nsRange.h"
#include "nsISelection.h"
#include "nsIEnumerator.h"
#include "nsCRT.h"
#include "nsIEventStateManager.h"
#include "nsIPrivateDOMEvent.h"
#include "nsISizeOfHandler.h"
#include "nsDOMEvent.h"
#include "nsIDOMText.h"
#include "nsIDOMScriptObjectFactory.h"
#include "prprf.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsTextFragment.h"
#include "nsVoidArray.h"
#include "nsINameSpaceManager.h"
#include "nsITextContent.h"
class nsIDOMAttr;
class nsIDOMEventListener;
class nsIDOMNodeList;
class nsIEventListenerManager;
class nsIFrame;
class nsIStyleContext;
class nsIStyleRule;
class nsISupportsArray;
class nsIDOMText;
// XXX share all id's in this dir
NS_DEFINE_IID(kIDOMCharacterDataIID, NS_IDOMCHARACTERDATA_IID);
static NS_DEFINE_IID(kIPrivateDOMEventIID, NS_IPRIVATEDOMEVENT_IID);
static NS_DEFINE_IID(kIEnumeratorIID, NS_IENUMERATOR_IID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);
class nsAttributeContent : public nsITextContent, public nsIAttributeContent {
public:
friend nsresult NS_NewAttributeContent(nsAttributeContent** aNewFrame);
nsAttributeContent();
virtual ~nsAttributeContent();
NS_IMETHOD Init(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttrName);
// nsISupports
NS_DECL_ISUPPORTS
// Implementation for nsIContent
NS_IMETHOD GetDocument(nsIDocument*& aResult) const;
NS_IMETHOD SetDocument(nsIDocument* aDocument, PRBool aDeep, PRBool aCompileEventHandlers);
NS_IMETHOD GetParent(nsIContent*& aResult) const;
NS_IMETHOD SetParent(nsIContent* aParent);
NS_IMETHOD IsSynthetic(PRBool& aResult) {
aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHOD GetNameSpaceID(PRInt32& aID) const {
aID = kNameSpaceID_None;
return NS_OK;
}
NS_IMETHOD GetTag(nsIAtom*& aResult) const {
aResult = nsnull;
return NS_OK;
}
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 SetFocus(nsIPresContext* aPresContext) { return NS_OK; }
NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext) { return NS_OK; }
NS_IMETHOD GetBindingParent(nsIContent** aContent) {
return NS_OK;
}
NS_IMETHOD SetBindingParent(nsIContent* aParent) {
return NS_OK;
}
NS_IMETHOD SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute, const nsAReadableString& aValue,
PRBool aNotify) { return NS_OK; }
NS_IMETHOD SetAttribute(nsINodeInfo *aNodeInfo, const nsAReadableString& aValue,
PRBool aNotify) { return NS_OK; }
NS_IMETHOD UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify) { return NS_OK; }
NS_IMETHOD GetAttribute(PRInt32 aNameSpaceID, nsIAtom *aAttribute, nsAWritableString& aResult) const {return NS_CONTENT_ATTR_NOT_THERE; }
NS_IMETHOD GetAttribute(PRInt32 aNameSpaceID, nsIAtom *aAttribute, nsIAtom*& aPrefix, nsAWritableString& aResult) const {return NS_CONTENT_ATTR_NOT_THERE; }
NS_IMETHOD GetAttributeNameAt(PRInt32 aIndex, PRInt32& aNameSpaceID, nsIAtom*& aName, nsIAtom*& aPrefix) const {
aName = nsnull;
aPrefix = nsnull;
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IMETHOD GetAttributeCount(PRInt32& aResult) const { aResult = 0; return NS_OK; }
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const { return NS_OK; }
NS_IMETHOD DumpContent(FILE* out, PRInt32 aIndent,PRBool aDumpAll) const { return NS_OK; }
NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus);
NS_IMETHOD GetContentID(PRUint32* aID) {
*aID = 0;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD SetContentID(PRUint32 aID) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD RangeAdd(nsIDOMRange& aRange);
NS_IMETHOD RangeRemove(nsIDOMRange& aRange);
NS_IMETHOD GetRangeList(nsVoidArray*& aResult) const;
// Implementation for nsIContent
NS_IMETHOD CanContainChildren(PRBool& aResult) const { aResult = PR_FALSE; return NS_OK; }
NS_IMETHOD ChildCount(PRInt32& aResult) const { aResult = 0; return NS_OK; }
NS_IMETHOD ChildAt(PRInt32 aIndex, nsIContent*& aResult) const { aResult = nsnull; return NS_OK; }
NS_IMETHOD IndexOf(nsIContent* aPossibleChild, PRInt32& aResult) const { aResult = -1; return NS_OK; }
NS_IMETHOD InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify) { return NS_OK; }
NS_IMETHOD ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify) { return NS_OK; }
NS_IMETHOD AppendChildTo(nsIContent* aKid, PRBool aNotify) { return NS_OK; }
NS_IMETHOD RemoveChildAt(PRInt32 aIndex, PRBool aNotify) { return NS_OK; }
NS_IMETHOD SplitText(PRUint32 aOffset, nsIDOMText** aReturn){ return NS_OK; }
///////////////////
// Implementation for nsITextContent
NS_IMETHOD GetText(const nsTextFragment** aFragmentsResult);
NS_IMETHOD GetTextLength(PRInt32* aLengthResult);
NS_IMETHOD CopyText(nsAWritableString& 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);
NS_IMETHOD CloneContent(PRBool aCloneText, nsITextContent** aClone);
//----------------------------------------
void ValidateTextFragment();
void ToCString(nsAWritableString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
// Up pointer to the real content object that we are
// supporting. Sometimes there is work that we just can't do
// ourselves, so this is needed to ask the real object to do the
// work.
nsIContent* mContent;
nsIDocument* mDocument;
nsIContent* mParent;
nsTextFragment mText;
PRInt32 mNameSpaceID;
nsIAtom* mAttrName;
};
NS_IMPL_ADDREF(nsAttributeContent)
NS_IMPL_RELEASE(nsAttributeContent)
nsresult
NS_NewAttributeContent(nsIContent** aContent)
{
NS_PRECONDITION(aContent, "null OUT ptr");
if (nsnull == aContent) {
return NS_ERROR_NULL_POINTER;
}
nsAttributeContent* it = new nsAttributeContent;
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_SUCCEEDED(it->QueryInterface(NS_GET_IID(nsIContent), (void **)aContent)) ?
NS_OK : NS_ERROR_FAILURE;
}
//----------------------------------------------------------------------
nsAttributeContent::nsAttributeContent()
: mText()
{
NS_INIT_REFCNT();
mDocument = nsnull;
mParent = nsnull;
mContent = nsnull;
mAttrName = nsnull;
}
//----------------------------------------------------------------------
nsAttributeContent::~nsAttributeContent()
{
NS_IF_RELEASE(mAttrName);
//NS_IF_RELEASE(mDocument);
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsAttributeContent::Init(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttrName)
{
NS_ASSERTION((nsnull == mContent) && (nsnull != aContent), "null ptr");
mContent = aContent;
NS_IF_RELEASE(mAttrName);
mNameSpaceID = aNameSpaceID;
mAttrName = aAttrName;
NS_ADDREF(mAttrName);
return NS_OK;
}
/**
* @param aIID The name of the class implementing the method
* @param _classiiddef The name of the #define symbol that defines the IID
* for the class (e.g. NS_ISUPPORTS_IID)
*
*/
nsresult nsAttributeContent::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(NS_GET_IID(nsIContent))) {
*aInstancePtr = (void*) ((nsIContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsITextContent))) {
*aInstancePtr = (void*) ((nsITextContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIAttributeContent))) {
*aInstancePtr = (void*) ((nsIAttributeContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = (void*) ((nsISupports*)(nsIContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
//----------------------------------------------------------------------
// Implementation of nsIContent
void
nsAttributeContent::ToCString(nsAWritableString& aBuf, PRInt32 aOffset,
PRInt32 aLen) const
{
}
nsresult
nsAttributeContent::GetDocument(nsIDocument*& aResult) const
{
aResult = mDocument;
NS_IF_ADDREF(mDocument);
return NS_OK;
}
nsresult
nsAttributeContent::SetDocument(nsIDocument* aDocument, PRBool aDeep, PRBool aCompileEventHandlers)
{
mDocument = aDocument;
//NS_IF_ADDREF(mDocument);
return NS_OK;
}
nsresult
nsAttributeContent::GetParent(nsIContent*& aResult) const
{
NS_IF_ADDREF(mParent);
aResult = mParent;
return NS_OK;;
}
nsresult
nsAttributeContent::SetParent(nsIContent* aParent)
{
mParent = aParent;
return NS_OK;
}
nsresult
nsAttributeContent::HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus)
{
nsresult ret = NS_OK;
return ret;
}
nsresult
nsAttributeContent::RangeAdd(nsIDOMRange& aRange)
{
return NS_ERROR_FAILURE;
}
nsresult
nsAttributeContent::RangeRemove(nsIDOMRange& aRange)
{
return NS_ERROR_FAILURE;
}
nsresult
nsAttributeContent::GetRangeList(nsVoidArray*& aResult) const
{
return NS_ERROR_FAILURE;
}
//----------------------------------------------------------------------
// Implementation of the nsITextContent interface
void
nsAttributeContent::ValidateTextFragment()
{
if (nsnull != mContent) {
nsAutoString result;
mContent->GetAttribute(mNameSpaceID, mAttrName, result);
PRUnichar * text = result.ToNewUnicode();
mText.SetTo(text, result.Length());
nsCRT::free(text);
}
else {
mText.SetTo("", 0);
}
}
nsresult
nsAttributeContent::GetText(const nsTextFragment** aFragmentsResult)
{
ValidateTextFragment();
if (nsnull != mContent) {
*aFragmentsResult = &mText;
return NS_OK;
}
// XXX is this a good idea, or should we just return an empty
// fragment with no data in it?
return NS_ERROR_FAILURE;
}
nsresult
nsAttributeContent::GetTextLength(PRInt32* aLengthResult)
{
if (!aLengthResult) {
return NS_ERROR_NULL_POINTER;
}
ValidateTextFragment();
*aLengthResult = mText.GetLength();
return NS_OK;
}
nsresult
nsAttributeContent::CopyText(nsAWritableString& aResult)
{
ValidateTextFragment();
if (mText.Is2b()) {
aResult.Assign(mText.Get2b(), mText.GetLength());
}
else {
aResult.Assign(NS_ConvertASCIItoUCS2(mText.Get1b(), mText.GetLength()).get(), mText.GetLength());
}
return NS_OK;
}
// XXX shouldn't these update mContent's attribute?
nsresult
nsAttributeContent::SetText(const PRUnichar* aBuffer, PRInt32 aLength,
PRBool aNotify)
{
NS_PRECONDITION((aLength >= 0) && (nsnull != aBuffer), "bad args");
if (aLength < 0) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
nsAttributeContent::SetText(const nsAReadableString& aStr,
PRBool aNotify)
{
mText = aStr;
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
}
return NS_OK;
}
// XXX shouldn't these update mContent's attribute?
nsresult
nsAttributeContent::SetText(const char* aBuffer,
PRInt32 aLength,
PRBool aNotify)
{
NS_PRECONDITION((aLength >= 0) && (nsnull != aBuffer), "bad args");
if (aLength < 0) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
}
return NS_OK;
}
nsresult
nsAttributeContent::IsOnlyWhitespace(PRBool* aResult)
{
ValidateTextFragment();
nsTextFragment& frag = mText;
if (frag.Is2b()) {
const PRUnichar* cp = frag.Get2b();
const PRUnichar* end = cp + frag.GetLength();
while (cp < end) {
PRUnichar ch = *cp++;
if (!XP_IS_SPACE(ch)) {
*aResult = PR_FALSE;
return NS_OK;
}
}
}
else {
const char* cp = frag.Get1b();
const char* end = cp + frag.GetLength();
while (cp < end) {
PRUnichar ch = PRUnichar(*(unsigned char*)cp);
cp++;
if (!XP_IS_SPACE(ch)) {
*aResult = PR_FALSE;
return NS_OK;
}
}
}
*aResult = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsAttributeContent::CloneContent(PRBool aCloneText, nsITextContent** aReturn)
{
nsresult result = NS_OK;
nsAttributeContent* it;
NS_NEWXPCOM(it, nsAttributeContent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
result = it->QueryInterface(kITextContentIID, (void**) aReturn);
if (NS_FAILED(result)) {
return result;
}
result = it->Init(mContent, mNameSpaceID, mAttrName);
if (NS_FAILED(result) || !aCloneText) {
return result;
}
it->mText = mText;
return result;
}
NS_IMETHODIMP
nsAttributeContent::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const
{
if (!aResult) return NS_ERROR_NULL_POINTER;
*aResult = sizeof(*this);
return NS_OK;
}