gecko-dev/content/base/src/nsGenericDOMDataNode.cpp

980 lines
26 KiB
C++
Raw Normal View History

1998-09-06 00:16:36 +00:00
/* -*- 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.
*/
1998-09-06 04:16:22 +00:00
#include "nsGenericDOMDataNode.h"
#include "nsGenericElement.h"
#include "nsIDocument.h"
1998-09-06 00:16:36 +00:00
#include "nsIEventListenerManager.h"
#include "nsIDocument.h"
#include "nsIDOMRange.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentFragment.h"
1998-09-06 00:16:36 +00:00
#include "nsXIFConverter.h"
#include "nsRange.h"
#include "nsIDOMSelection.h"
#include "nsIEnumerator.h"
1998-09-06 00:16:36 +00:00
#include "nsCRT.h"
#include "nsIEventStateManager.h"
#include "nsIPrivateDOMEvent.h"
#include "nsISizeOfHandler.h"
#include "nsDOMEvent.h"
#include "nsIDOMText.h"
1998-09-10 17:11:46 +00:00
#include "nsIDOMScriptObjectFactory.h"
#include "nsIScriptContextOwner.h"
1998-09-29 22:34:30 +00:00
#include "prprf.h"
#include "nsCOMPtr.h"
1998-09-06 00:16:36 +00:00
// XXX share all id's in this dir
NS_DEFINE_IID(kIDOMCharacterDataIID, NS_IDOMCHARACTERDATA_IID);
1998-09-06 00:16:36 +00:00
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);
static NS_DEFINE_IID(kIDOMNodeListIID, NS_IDOMNODELIST_IID);
1998-09-06 00:16:36 +00:00
//----------------------------------------------------------------------
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::nsGenericDOMDataNode()
: mText()
1998-09-06 00:16:36 +00:00
{
mDocument = nsnull;
mParent = nsnull;
mContent = nsnull;
mScriptObject = nsnull;
mListenerManager = nsnull;
mRangeList = nsnull;
mCapturer = nsnull;
1998-09-06 00:16:36 +00:00
}
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::~nsGenericDOMDataNode()
1998-09-06 00:16:36 +00:00
{
NS_IF_RELEASE(mListenerManager);
delete mRangeList;
1998-09-06 00:16:36 +00:00
}
void
nsGenericDOMDataNode::Init(nsIContent* aOuterContentObject)
1998-09-06 00:16:36 +00:00
{
NS_ASSERTION((nsnull == mContent) && (nsnull != aOuterContentObject),
"null ptr");
mContent = aOuterContentObject;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetNodeValue(nsString& aNodeValue)
1998-09-06 00:16:36 +00:00
{
return GetData(aNodeValue);
1998-09-06 00:16:36 +00:00
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::SetNodeValue(const nsString& aNodeValue)
1998-09-06 00:16:36 +00:00
{
return SetData(aNodeValue);
1998-09-06 00:16:36 +00:00
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetParentNode(nsIDOMNode** aParentNode)
1998-09-06 00:16:36 +00:00
{
nsresult res = NS_OK;
1998-09-06 00:16:36 +00:00
if (nsnull != mParent) {
res = mParent->QueryInterface(kIDOMNodeIID, (void**)aParentNode);
1998-09-06 00:16:36 +00:00
NS_ASSERTION(NS_OK == res, "Must be a DOM Node");
}
else if (nsnull == mDocument) {
*aParentNode = nsnull;
}
1998-09-06 00:16:36 +00:00
else {
// If we don't have a parent, but we're in the document, we must
// be the root node of the document. The DOM says that the root
// is the document.
res = mDocument->QueryInterface(kIDOMNodeIID, (void**)aParentNode);
1998-09-06 00:16:36 +00:00
}
return res;
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
1998-09-06 00:16:36 +00:00
{
nsIContent* sibling = nsnull;
nsresult result = NS_OK;
1998-09-06 00:16:36 +00:00
if (nsnull != mParent) {
PRInt32 pos;
mParent->IndexOf(mContent, pos);
if (pos > -1 ) {
mParent->ChildAt(--pos, sibling);
1998-09-06 00:16:36 +00:00
}
}
else if (nsnull != mDocument) {
// Nodes that are just below the document (their parent is the
// document) need to go to the document to find their next sibling.
PRInt32 pos;
mDocument->IndexOf(mContent, pos);
if (pos > -1 ) {
mDocument->ChildAt(--pos, sibling);
}
}
if (nsnull != sibling) {
result = sibling->QueryInterface(kIDOMNodeIID,(void**)aPrevSibling);
NS_ASSERTION(NS_OK == result, "Must be a DOM Node");
NS_RELEASE(sibling); // balance the AddRef in ChildAt()
}
else {
*aPrevSibling = nsnull;
}
return result;
1998-09-06 00:16:36 +00:00
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetNextSibling(nsIDOMNode** aNextSibling)
1998-09-06 00:16:36 +00:00
{
nsIContent* sibling = nsnull;
nsresult result = NS_OK;
1998-09-06 00:16:36 +00:00
if (nsnull != mParent) {
PRInt32 pos;
mParent->IndexOf(mContent, pos);
if (pos > -1 ) {
mParent->ChildAt(++pos, sibling);
1998-09-06 00:16:36 +00:00
}
}
else if (nsnull != mDocument) {
// Nodes that are just below the document (their parent is the
// document) need to go to the document to find their next sibling.
PRInt32 pos;
mDocument->IndexOf(mContent, pos);
if (pos > -1 ) {
mDocument->ChildAt(++pos, sibling);
}
}
if (nsnull != sibling) {
result = sibling->QueryInterface(kIDOMNodeIID,(void**)aNextSibling);
NS_ASSERTION(NS_OK == result, "Must be a DOM Node");
NS_RELEASE(sibling); // balance the AddRef in ChildAt()
}
else {
*aNextSibling = nsnull;
}
return result;
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::GetChildNodes(nsIDOMNodeList** aChildNodes)
{
// XXX Since we believe this won't be done very often, we won't
// burn another slot in the data node and just create a new
// (empty) childNodes list every time we're asked.
nsChildContentList* list = new nsChildContentList(nsnull);
if (nsnull == list) {
return NS_ERROR_OUT_OF_MEMORY;
}
return list->QueryInterface(kIDOMNodeListIID, (void**)aChildNodes);
}
nsresult
nsGenericDOMDataNode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
{
// XXX Actually the owner document is the document in whose context
// the node has been created. We should be able to get at it
// whether or not we are attached to the document.
if (nsnull != mDocument) {
return mDocument->QueryInterface(kIDOMDocumentIID, (void **)aOwnerDocument);
}
else {
*aOwnerDocument = nsnull;
return NS_OK;
}
}
1998-09-06 00:16:36 +00:00
#if 0
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::Equals(nsIDOMNode* aNode, PRBool aDeep, PRBool* aReturn)
1998-09-06 00:16:36 +00:00
{
*aReturn = PR_FALSE;
PRInt32 nt1, nt2;
GetNodeType(&nt1);
aNode->GetNodeType(&nt2);
if (nt1 != nt2) {
return NS_OK;
}
return NS_OK;
}
#endif
//----------------------------------------------------------------------
// Implementation of nsIDOMCharacterData
1998-09-06 00:16:36 +00:00
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetData(nsString& aData)
1998-09-06 00:16:36 +00:00
{
if (mText.Is2b()) {
aData.SetString(mText.Get2b(), mText.GetLength());
}
else {
aData.SetString(mText.Get1b(), mText.GetLength());
1998-09-06 00:16:36 +00:00
}
return NS_OK;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::SetData(const nsString& aData)
1998-09-06 00:16:36 +00:00
{
// inform any enclosed ranges of change
// we can lie and say we are deleting all the text, since in a total
// text replacement we should just collapse all the ranges.
if (mRangeList) nsRange::TextOwnerChanged(mContent, 0, mText.GetLength(), 0);
1998-09-06 00:16:36 +00:00
nsresult result;
nsCOMPtr<nsITextContent> textContent = do_QueryInterface(mContent, &result);
// If possible, let the container content object have a go at it.
if (NS_SUCCEEDED(result)) {
result = textContent->SetText(aData.GetUnicode(),
aData.Length(),
PR_TRUE);
1998-09-06 00:16:36 +00:00
}
else {
result = SetText(aData.GetUnicode(), aData.Length(), PR_TRUE);
}
return result;
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::GetLength(PRUint32* aLength)
1998-09-06 00:16:36 +00:00
{
*aLength = mText.GetLength();
1998-09-06 00:16:36 +00:00
return NS_OK;
}
// XXX temporary; none of these methods try to return error codes as
// per the spec
1998-09-06 00:16:36 +00:00
#define NS_DOM_INDEX_SIZE_ERR NS_ERROR_FAILURE
nsresult
nsGenericDOMDataNode::SubstringData(PRUint32 aStart,
PRUint32 aCount,
nsString& aReturn)
1998-09-06 00:16:36 +00:00
{
aReturn.Truncate();
// XXX add <0 checks if types change
PRUint32 textLength = PRUint32( mText.GetLength() );
if (aStart >= textLength) {
return NS_DOM_INDEX_SIZE_ERR;
1998-09-06 00:16:36 +00:00
}
PRUint32 amount = aCount;
if (aStart + amount > textLength) {
amount = textLength - aStart;
}
if (mText.Is2b()) {
aReturn.SetString(mText.Get2b() + aStart, amount);
}
else {
aReturn.SetString(mText.Get1b() + aStart, amount);
}
1998-09-06 00:16:36 +00:00
return NS_OK;
}
nsresult
nsGenericDOMDataNode::AppendData(const nsString& aData)
1998-09-06 00:16:36 +00:00
{
return ReplaceData(mText.GetLength(), 0, aData);
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::InsertData(PRUint32 aOffset, const nsString& aData)
1998-09-06 00:16:36 +00:00
{
return ReplaceData(aOffset, 0, aData);
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::DeleteData(PRUint32 aOffset, PRUint32 aCount)
1998-09-06 00:16:36 +00:00
{
nsAutoString empty;
return ReplaceData(aOffset, aCount, empty);
1998-09-06 00:16:36 +00:00
}
nsresult
nsGenericDOMDataNode::ReplaceData(PRUint32 aOffset, PRUint32 aCount,
const nsString& aData)
1998-09-06 00:16:36 +00:00
{
nsresult result = NS_OK;
1998-09-06 00:16:36 +00:00
// sanitize arguments
PRUint32 textLength = mText.GetLength();
if (aOffset > textLength) {
aOffset = textLength;
1998-09-06 00:16:36 +00:00
}
// Allocate new buffer
PRUint32 endOffset = aOffset + aCount;
if (endOffset > textLength) {
aCount = textLength - aOffset;
endOffset = textLength;
1998-09-06 00:16:36 +00:00
}
PRInt32 dataLength = aData.Length();
PRInt32 newLength = textLength - aCount + dataLength;
1998-09-06 00:16:36 +00:00
PRUnichar* to = new PRUnichar[newLength ? newLength : 1];
if (nsnull == to) {
return NS_ERROR_OUT_OF_MEMORY;
}
// inform any enclosed ranges of change
if (mRangeList) nsRange::TextOwnerChanged(mContent, aOffset, endOffset, dataLength);
1998-09-06 00:16:36 +00:00
// Copy over appropriate data
if (0 != aOffset) {
mText.CopyTo(to, 0, aOffset);
1998-09-06 00:16:36 +00:00
}
if (0 != dataLength) {
nsCRT::memcpy(to + aOffset, aData.GetUnicode(),
sizeof(PRUnichar) * dataLength);
}
if (endOffset != textLength) {
mText.CopyTo(to + aOffset + dataLength, endOffset, textLength - endOffset);
1998-09-06 00:16:36 +00:00
}
// Switch to new buffer
nsCOMPtr<nsITextContent> textContent = do_QueryInterface(mContent, &result);
1998-09-06 00:16:36 +00:00
// If possible, let the container content object have a go at it.
if (NS_SUCCEEDED(result)) {
result = textContent->SetText(to, newLength, PR_TRUE);
}
else {
result = SetText(to, newLength, PR_TRUE);
1998-09-06 00:16:36 +00:00
}
delete [] to;
1998-09-06 00:16:36 +00:00
return result;
1998-09-06 00:16:36 +00:00
}
//----------------------------------------------------------------------
// nsIScriptObjectOwner implementation
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetScriptObject(nsIScriptContext* aContext,
1998-09-06 00:16:36 +00:00
void** aScriptObject)
{
nsresult res = NS_OK;
if (nsnull == mScriptObject) {
1998-09-10 17:11:46 +00:00
nsIDOMScriptObjectFactory *factory;
res = nsGenericElement::GetScriptObjectFactory(&factory);
1998-09-10 17:11:46 +00:00
if (NS_OK != res) {
return res;
}
nsIDOMNode* node;
PRUint16 nodeType;
res = mContent->QueryInterface(kIDOMNodeIID, (void**)&node);
if (NS_OK != res) {
return res;
}
node->GetNodeType(&nodeType);
res = factory->NewScriptCharacterData(nodeType,
aContext, mContent,
mParent, (void**)&mScriptObject);
if (nsnull != mDocument) {
nsAutoString nodeName;
char nameBuf[128];
node->GetNodeName(nodeName);
nodeName.ToCString(nameBuf, sizeof(nameBuf));
aContext->AddNamedReference((void *)&mScriptObject,
mScriptObject,
nameBuf);
}
NS_RELEASE(node);
1998-09-10 17:11:46 +00:00
NS_RELEASE(factory);
1998-09-06 00:16:36 +00:00
}
*aScriptObject = mScriptObject;
return res;
}
nsresult
nsGenericDOMDataNode::SetScriptObject(void *aScriptObject)
1998-09-06 00:16:36 +00:00
{
mScriptObject = aScriptObject;
1998-09-06 00:16:36 +00:00
return NS_OK;
}
//----------------------------------------------------------------------
// nsIDOMEventReceiver implementation
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetListenerManager(nsIEventListenerManager** aResult)
1998-09-06 00:16:36 +00:00
{
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
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetNewListenerManager(nsIEventListenerManager** aResult)
1998-09-06 00:16:36 +00:00
{
return NS_NewEventListenerManager(aResult);
}
nsresult
nsGenericDOMDataNode::AddEventListenerByIID(nsIDOMEventListener* aListener,
1998-09-06 00:16:36 +00:00
const nsIID& aIID)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
1998-09-06 00:16:36 +00:00
NS_RELEASE(manager);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
nsGenericDOMDataNode::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
1998-09-06 00:16:36 +00:00
const nsIID& aIID)
{
if (nsnull != mListenerManager) {
mListenerManager->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
nsGenericDOMDataNode::AddEventListener(const nsString& aType, nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
manager->AddEventListenerByType(aListener, aType, flags);
NS_RELEASE(manager);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
nsGenericDOMDataNode::RemoveEventListener(const nsString& aType, nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
if (nsnull != mListenerManager) {
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
mListenerManager->RemoveEventListenerByType(aListener, aType, flags);
1998-09-06 00:16:36 +00:00
return NS_OK;
}
return NS_ERROR_FAILURE;
}
//----------------------------------------------------------------------
// Implementation of nsIContent
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::BeginConvertToXIF(nsXIFConverter& aConverter) const
1998-09-06 00:16:36 +00:00
{
return NS_OK;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::FinishConvertToXIF(nsXIFConverter& aConverter) const
1998-09-06 00:16:36 +00:00
{
return NS_OK;
}
/**
* Translate the content object into the (XIF) XML Interchange Format
* XIF is an intermediate form of the content model, the buffer
* will then be parsed into any number of formats including HTML, TXT, etc.
*/
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::ConvertContentToXIF(nsXIFConverter& aConverter) const
1998-09-06 00:16:36 +00:00
{
const nsIContent* content = mContent;
nsIDOMSelection* sel = aConverter.GetSelection();
1998-09-06 00:16:36 +00:00
if (sel != nsnull && mDocument->IsInSelection(sel,content))
1998-09-06 00:16:36 +00:00
{
nsIEnumerator *enumerator;
if (NS_SUCCEEDED(sel->QueryInterface(kIEnumeratorIID, (void **)&enumerator))) {
for (enumerator->First();NS_OK != enumerator->IsDone(); enumerator->Next()) {
nsIDOMRange* range = nsnull;
if (NS_SUCCEEDED(enumerator->CurrentItem((nsISupports**)&range))) {
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset = 0;
PRInt32 endOffset = 0;
range->GetStartParent(getter_AddRefs(startNode));
range->GetEndParent(getter_AddRefs(endNode));
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIContent> startContent;
nsCOMPtr<nsIContent> endContent;
startContent = do_QueryInterface(startNode);
endContent = do_QueryInterface(endNode);
nsString buffer;
mText.AppendTo(buffer);
if (startContent.get() == content || endContent.get() == content)
{
// NOTE: ORDER MATTERS!
// This must go before the Cut
if (endContent.get() == content)
buffer.Truncate(endOffset);
// This must go after the Trunctate
if (startContent.get() == content)
buffer.Cut(0,startOffset);
}
aConverter.AddContent(buffer);
1998-09-06 00:16:36 +00:00
}
}
}
}
else
{
nsString buffer;
mText.AppendTo(buffer);
1998-09-06 00:16:36 +00:00
aConverter.AddContent(buffer);
}
return NS_OK;
}
void
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::ToCString(nsString& aBuf, PRInt32 aOffset,
1998-09-06 00:16:36 +00:00
PRInt32 aLen) const
{
if (mText.Is2b()) {
const PRUnichar* cp = mText.Get2b() + aOffset;
const PRUnichar* end = cp + aLen;
while (cp < end) {
PRUnichar ch = *cp++;
if (ch == '\r') {
aBuf.Append("\\r");
} else if (ch == '\n') {
aBuf.Append("\\n");
} else if (ch == '\t') {
aBuf.Append("\\t");
} else if ((ch < ' ') || (ch >= 127)) {
char buf[10];
PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
aBuf.Append(buf);
} else {
aBuf.Append(ch);
}
}
}
else {
unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
const unsigned char* end = cp + aLen;
while (cp < end) {
PRUnichar ch = *cp++;
if (ch == '\r') {
aBuf.Append("\\r");
} else if (ch == '\n') {
aBuf.Append("\\n");
} else if (ch == '\t') {
aBuf.Append("\\t");
} else if ((ch < ' ') || (ch >= 127)) {
char buf[10];
PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
aBuf.Append(buf);
} else {
aBuf.Append(ch);
}
1998-09-06 00:16:36 +00:00
}
}
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetDocument(nsIDocument*& aResult) const
1998-09-06 00:16:36 +00:00
{
aResult = mDocument;
NS_IF_ADDREF(mDocument);
return NS_OK;
}
1998-09-06 00:16:36 +00:00
nsresult
nsGenericDOMDataNode::SetDocument(nsIDocument* aDocument, PRBool aDeep)
{
// If we were part of a document, make sure we get rid of the
// script context reference to our script object so that our
// script object can be freed (or collected).
if ((nsnull != mDocument) && (nsnull != mScriptObject)) {
nsIScriptContextOwner *owner = mDocument->GetScriptContextOwner();
if (nsnull != owner) {
nsIScriptContext *context;
if (NS_OK == owner->GetScriptContext(&context)) {
context->RemoveReference((void *)&mScriptObject,
mScriptObject);
NS_RELEASE(context);
}
NS_RELEASE(owner);
}
}
1998-09-06 00:16:36 +00:00
mDocument = aDocument;
// If we already have a script object and now we're being added
// to a document, make sure that the script context adds a
// reference to our script object. This will ensure that it
// won't be freed (or collected) out from under us.
if ((nsnull != mDocument) && (nsnull != mScriptObject)) {
nsIScriptContextOwner *owner = mDocument->GetScriptContextOwner();
if (nsnull != owner) {
nsIScriptContext *context;
if (NS_OK == owner->GetScriptContext(&context)) {
context->AddNamedReference((void *)&mScriptObject,
mScriptObject,
"Text");
NS_RELEASE(context);
}
NS_RELEASE(owner);
}
}
1998-09-06 00:16:36 +00:00
return NS_OK;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::GetParent(nsIContent*& aResult) const
1998-09-06 00:16:36 +00:00
{
NS_IF_ADDREF(mParent);
aResult = mParent;
return NS_OK;;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::SetParent(nsIContent* aParent)
1998-09-06 00:16:36 +00:00
{
mParent = aParent;
return NS_OK;
}
nsresult
1998-09-06 04:16:22 +00:00
nsGenericDOMDataNode::HandleDOMEvent(nsIPresContext& aPresContext,
1998-09-06 00:16:36 +00:00
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus& aEventStatus)
{
nsresult ret = NS_OK;
nsIDOMEvent* domEvent = nsnull;
if (NS_EVENT_FLAG_INIT == aFlags) {
1998-09-06 00:16:36 +00:00
aDOMEvent = &domEvent;
aEvent->flags = NS_EVENT_FLAG_NONE;
//Initiate capturing phase. Special case first call to document
if (nsnull != mDocument) {
mDocument->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, NS_EVENT_FLAG_CAPTURE, aEventStatus);
}
1998-09-06 00:16:36 +00:00
}
//Capturing stage evaluation
//Always pass capturing up the tree before local evaulation
if (NS_EVENT_FLAG_BUBBLE != aFlags && nsnull != mCapturer) {
mCapturer->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, NS_EVENT_FLAG_CAPTURE, aEventStatus);
}
1998-09-06 00:16:36 +00:00
//Local handling stage
if (!(aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) && nsnull != mListenerManager) {
mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aFlags, aEventStatus);
1998-09-06 00:16:36 +00:00
}
//Bubbling stage
if (NS_EVENT_FLAG_CAPTURE != aFlags && mParent != nsnull) {
1998-09-06 00:16:36 +00:00
ret = mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
NS_EVENT_FLAG_BUBBLE, aEventStatus);
1998-09-06 00:16:36 +00:00
}
if (NS_EVENT_FLAG_INIT == aFlags) {
1998-09-06 00:16:36 +00:00
// 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
nsGenericDOMDataNode::RangeAdd(nsIDOMRange& aRange)
{
// lazy allocation of range list
if (nsnull == mRangeList) {
mRangeList = new nsVoidArray();
}
if (nsnull == mRangeList) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Make sure we don't add a range that is already
// in the list!
PRInt32 i = mRangeList->IndexOf(&aRange);
if (i >= 0) {
// Range is already in the list, so there
// is nothing to do!
return NS_OK;
}
// dont need to addref - this call is made by the range object itself
PRBool rv = mRangeList->AppendElement(&aRange);
if (rv) return NS_OK;
return NS_ERROR_FAILURE;
}
nsresult
nsGenericDOMDataNode::RangeRemove(nsIDOMRange& aRange)
{
if (mRangeList) {
// dont need to release - this call is made by the range object itself
PRBool rv = mRangeList->RemoveElement(&aRange);
1998-12-18 02:51:34 +00:00
if (rv) {
if (mRangeList->Count() == 0) {
delete mRangeList;
mRangeList = nsnull;
1998-12-18 02:51:34 +00:00
}
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
1998-12-18 02:51:34 +00:00
nsresult
nsGenericDOMDataNode::GetRangeList(nsVoidArray*& aResult) const
{
aResult = mRangeList;
return NS_OK;
}
//----------------------------------------------------------------------
// Implementation of the nsIDOMText interface
nsresult
nsGenericDOMDataNode::SplitText(PRUint32 aOffset, nsIDOMText** aReturn)
{
nsresult result = NS_OK;
nsIContent* newNode;
nsITextContent* text;
nsAutoString cutText;
nsIContent* parentNode;
PRUint32 length;
GetLength(&length);
// Cut the second part out of the original text node
result = SubstringData(aOffset, length-aOffset, cutText);
if (NS_OK == result) {
result = DeleteData(aOffset, length-aOffset);
if (NS_OK == result) {
// Create a new text node and set its data to the
// string we just cut out
result = NS_NewTextNode(&newNode);
if (NS_OK == result) {
result = newNode->QueryInterface(kITextContentIID, (void**)&text);
if (NS_OK == result) {
1999-04-21 23:12:55 +00:00
text->SetText(cutText.GetUnicode(), cutText.Length(), PR_FALSE);
// Find the parent of the current node and insert the
// new text node as a child after the current node
GetParent(parentNode);
if (nsnull != parentNode) {
PRInt32 index;
result = parentNode->IndexOf(mContent, index);
if (NS_OK == result) {
result = parentNode->InsertChildAt(newNode, index+1, PR_TRUE);
}
NS_RELEASE(parentNode);
}
result = text->QueryInterface(kIDOMTextIID, (void**)aReturn);
NS_RELEASE(text);
}
NS_RELEASE(newNode);
}
}
}
return result;
}
//----------------------------------------------------------------------
// Implementation of the nsITextContent interface
nsresult
nsGenericDOMDataNode::GetText(const nsTextFragment*& aFragmentsResult,
PRInt32& aNumFragmentsResult)
{
aFragmentsResult = &mText;
aNumFragmentsResult = 1;
return NS_OK;
}
nsresult
nsGenericDOMDataNode::GetTextLength(PRInt32* aLengthResult)
{
if (!aLengthResult) {
return NS_ERROR_NULL_POINTER;
}
*aLengthResult = mText.GetLength();
return NS_OK;
}
nsresult
nsGenericDOMDataNode::CopyText(nsString& aResult)
{
if (mText.Is2b()) {
aResult.SetString(mText.Get2b(), mText.GetLength());
}
else {
aResult.SetString(mText.Get1b(), mText.GetLength());
}
return NS_OK;
}
nsresult
nsGenericDOMDataNode::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;
}
nsresult
nsGenericDOMDataNode::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
nsGenericDOMDataNode::IsOnlyWhitespace(PRBool* aResult)
{
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;
}