Files
Mozilla/mozilla/layout/html/base/src/nsHTMLContent.cpp
kostello 99d792b211 Added XIF (XML Interchange Format) Support. XIF is designed
as an Netscape internal XML application. It is designed to
allow conversion from our content model to any output format --
most importantly to HTML 3.2 and HTML4.0 format.


git-svn-id: svn://10.0.0.236/trunk@5521 18797224-902f-48f8-a5cc-f745e15eee43
1998-07-14 22:34:27 +00:00

669 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsHTMLContent.h"
#include "nsString.h"
#include "nsIArena.h"
#include "nsIAtom.h"
#include "nsIHTMLAttributes.h"
#include "nsIContentDelegate.h"
#include "nsFrame.h"
#include "nsHTMLIIDs.h"
#include "nsISupportsArray.h"
#include "nsCRT.h"
#include "nsIDocument.h"
#include "nsIEventListenerManager.h"
#include "nsEventListenerManager.h"
#include "nsISizeOfHandler.h"
static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID);
static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);
static NS_DEFINE_IID(kIHTMLContent, NS_IHTMLCONTENT_IID);
static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID);
static NS_DEFINE_IID(kIEventListenerManagerIID, NS_IEVENTLISTENERMANAGER_IID);
static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
static nsIContentDelegate* gContentDelegate;
/**
* THE html content delegate. There is exactly one instance of this
* class and it's used for all html content. It just turns around
* and asks the content object to create the frame.
*/
class ContentDelegate : public nsIContentDelegate {
public:
ContentDelegate();
NS_DECL_ISUPPORTS
NS_IMETHOD CreateFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIStyleContext* aStyleContext,
nsIFrame*& aResult);
protected:
~ContentDelegate();
};
ContentDelegate::ContentDelegate()
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(ContentDelegate, kIContentDelegateIID);
ContentDelegate::~ContentDelegate()
{
}
NS_METHOD
ContentDelegate::CreateFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIStyleContext* aStyleContext,
nsIFrame*& aResult)
{
NS_PRECONDITION(nsnull != aContent, "null ptr");
// Make sure the content is html content
nsIHTMLContent* hc;
nsIFrame* frame = nsnull;
nsresult rv = aContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
if (NS_OK != rv) {
// This means that *somehow* somebody which is not an html
// content object got ahold of this delegate and tried to
// create a frame with it. Give them back an nsFrame.
rv = nsFrame::NewFrame(&frame, aContent, aParentFrame);
if (NS_OK == rv) {
frame->SetStyleContext(aPresContext, aStyleContext);
}
}
else {
// Ask the content object to create the frame
rv = hc->CreateFrame(aPresContext, aParentFrame, aStyleContext, frame);
NS_RELEASE(hc);
}
aResult = frame;
return rv;
}
//----------------------------------------------------------------------
void* nsHTMLContent::operator new(size_t size)
{
nsHTMLContent* rv = (nsHTMLContent*) ::operator new(size);
nsCRT::zero(rv, size);
rv->mInHeap = 1;
return (void*) rv;
}
void* nsHTMLContent::operator new(size_t size, nsIArena* aArena)
{
nsHTMLContent* rv = (nsHTMLContent*) aArena->Alloc(PRInt32(size));
nsCRT::zero(rv, size);
return (void*) rv;
}
void nsHTMLContent::operator delete(void* ptr)
{
NS_PRECONDITION(nsnull != ptr, "null ptr");
nsHTMLContent* hc = (nsHTMLContent*) ptr;
if (nsnull != hc) {
if (hc->mInHeap) {
::delete ptr;
}
}
}
nsHTMLContent::nsHTMLContent()
{
// Create shared content delegate if this is the first html content
// object being created.
if (nsnull == gContentDelegate) {
gContentDelegate = new ContentDelegate();
}
mListenerManager = nsnull;
// Add a reference to the shared content delegate object
NS_ADDREF(gContentDelegate);
}
nsHTMLContent::~nsHTMLContent()
{
NS_PRECONDITION(nsnull != gContentDelegate, "null content delegate");
if (nsnull != gContentDelegate) {
// Remove our reference to the shared content delegate object. If
// the last reference just went away, null out gContentDelegate.
nsrefcnt rc = gContentDelegate->Release();
if (0 == rc) {
gContentDelegate = nsnull;
}
}
}
NS_IMPL_ADDREF(nsHTMLContent)
NS_IMPL_RELEASE(nsHTMLContent)
nsresult nsHTMLContent::QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIHTMLContentIID)) {
*aInstancePtrResult = (void*) ((nsIHTMLContent*)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIContentIID)) {
*aInstancePtrResult = (void*) ((nsIContent*)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
*aInstancePtrResult = (void*)(nsISupports*)(nsIContent*)this;
AddRef();
return NS_OK;
}
if (aIID.Equals(kIDOMNodeIID)) {
*aInstancePtrResult = (void*)(nsIDOMNode*)this;
AddRef();
return NS_OK;
}
if (aIID.Equals(kIScriptObjectOwnerIID)) {
*aInstancePtrResult = (void*)(nsIScriptObjectOwner*)this;
AddRef();
return NS_OK;
}
if (aIID.Equals(kIDOMEventReceiverIID)) {
*aInstancePtrResult = (void*)(nsIDOMEventReceiver*)this;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_METHOD
nsHTMLContent::IsSynthetic(PRBool& aResult)
{
aResult = PR_FALSE;
return NS_OK;
}
void nsHTMLContent::Compact()
{
}
nsresult
nsHTMLContent::GetDocument(nsIDocument*& aResult) const
{
aResult = mDocument;
NS_IF_ADDREF(mDocument);
return NS_OK;
}
void nsHTMLContent::SetDocument(nsIDocument* aDocument)
{
mDocument = aDocument;
}
nsIContent* nsHTMLContent::GetParent() const
{
NS_IF_ADDREF(mParent);
return mParent;
}
void nsHTMLContent::SetParent(nsIContent* aParent)
{
mParent = aParent;
}
PRBool nsHTMLContent::CanContainChildren() const
{
return PR_FALSE;
}
PRInt32 nsHTMLContent::ChildCount() const
{
return 0;
}
nsIContent* nsHTMLContent::ChildAt(PRInt32 aIndex) const
{
return nsnull;
}
PRInt32 nsHTMLContent::IndexOf(nsIContent* aPossibleChild) const
{
return -1;
}
NS_IMETHODIMP
nsHTMLContent::InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::AppendChild(nsIContent* aKid, PRBool aNotify)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
{
return NS_OK;
}
void nsHTMLContent::SetAttribute(const nsString& aName, const nsString& aValue)
{
}
nsContentAttr nsHTMLContent::GetAttribute(const nsString& aName,
nsString& aResult) const
{
aResult.SetLength(0);
return eContentAttr_NotThere;
}
void nsHTMLContent::SetAttribute(nsIAtom* aAttribute, const nsString& aValue)
{
}
void nsHTMLContent::SetAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue)
{
}
void nsHTMLContent::UnsetAttribute(nsIAtom* aAttribute)
{
}
nsContentAttr nsHTMLContent::GetAttribute(nsIAtom* aAttribute,
nsHTMLValue& aValue) const
{
aValue.Reset();
return eContentAttr_NotThere;
}
PRInt32 nsHTMLContent::GetAllAttributeNames(nsISupportsArray* aArray) const
{
return 0;
}
PRInt32 nsHTMLContent::GetAttributeCount(void) const
{
return 0;
}
void nsHTMLContent::SetID(nsIAtom* aID)
{
}
nsIAtom* nsHTMLContent::GetID(void) const
{
return nsnull;
}
void nsHTMLContent::SetClass(nsIAtom* aClass)
{
}
nsIAtom* nsHTMLContent::GetClass(void) const
{
return nsnull;
}
nsIStyleRule* nsHTMLContent::GetStyleRule(void)
{
return nsnull;
}
void nsHTMLContent::MapAttributesInto(nsIStyleContext* aContext,
nsIPresContext* aPresContext)
{
}
void nsHTMLContent::ListAttributes(FILE* out) const
{
nsISupportsArray* attrs;
if (NS_OK == NS_NewISupportsArray(&attrs)) {
GetAllAttributeNames(attrs);
PRInt32 count = attrs->Count();
PRInt32 index;
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);
}
}
void nsHTMLContent::List(FILE* out, PRInt32 aIndent) const
{
NS_PRECONDITION(nsnull != mDocument, "bad content");
PRInt32 index;
for (index = aIndent; --index >= 0; ) fputs(" ", out);
nsIAtom* tag = GetTag();
if (tag != nsnull) {
nsAutoString buf;
tag->ToString(buf);
fputs(buf, out);
NS_RELEASE(tag);
}
ListAttributes(out);
fprintf(out, " RefCount=%d<\n", mRefCnt);
if (CanContainChildren()) {
PRInt32 kids = ChildCount();
for (index = 0; index < kids; index++) {
nsIContent* kid = ChildAt(index);
kid->List(out, aIndent + 1);
NS_RELEASE(kid);
}
}
for (index = aIndent; --index >= 0; ) fputs(" ", out);
fputs(">\n", out);
}
NS_IMETHODIMP
nsHTMLContent::SizeOf(nsISizeOfHandler* aHandler) const
{
aHandler->Add(sizeof(*this));
nsHTMLContent::SizeOfWithoutThis(aHandler);
return NS_OK;
}
void
nsHTMLContent::SizeOfWithoutThis(nsISizeOfHandler* aHandler) const
{
// XXX mScriptObject
}
nsIAtom* nsHTMLContent::GetTag() const
{
return nsnull;
}
void nsHTMLContent::ToHTML(FILE* out) const
{
nsAutoString tmp;
ToHTMLString(tmp);
fputs(tmp, out);
}
nsIContentDelegate* nsHTMLContent::GetDelegate(nsIPresContext* aCX)
{
gContentDelegate->AddRef();
return gContentDelegate;
}
void nsHTMLContent::NewGlobalAtom(const char* aString, nsIAtom** aAtomResult)
{
if (nsnull == *aAtomResult) {
*aAtomResult = NS_NewAtom(aString);
} else {
NS_ADDREF(*aAtomResult);
}
}
void nsHTMLContent::ReleaseGlobalAtom(nsIAtom** aAtomResult)
{
nsIAtom* atom = *aAtomResult;
if (nsnull != atom) {
if (0 == atom->Release()) {
*aAtomResult = nsnull;
}
}
}
nsresult nsHTMLContent::ResetScriptObject()
{
mScriptObject = nsnull;
return NS_OK;
}
//
// Implementation of nsIDOMNode interface
//
NS_IMETHODIMP
nsHTMLContent::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;
}
NS_IMETHODIMP
nsHTMLContent::GetChildNodes(nsIDOMNodeList** aChildNodes)
{
*aChildNodes = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::GetHasChildNodes(PRBool* aHasChildNodes)
{
*aHasChildNodes = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::GetFirstChild(nsIDOMNode** aFirstChild)
{
*aFirstChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::GetLastChild(nsIDOMNode** aLastChild)
{
*aLastChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::GetPreviousSibling(nsIDOMNode** aNode)
{
if (nsnull != mParent) {
PRInt32 pos = mParent->IndexOf(this);
if (pos > -1) {
nsIContent* prev = mParent->ChildAt(--pos);
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;
}
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHTMLContent::GetNextSibling(nsIDOMNode** aNextSibling)
{
if (nsnull != mParent) {
PRInt32 pos = mParent->IndexOf(this);
if (pos > -1 ) {
nsIContent* prev = mParent->ChildAt(++pos);
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;
}
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHTMLContent::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
{
aAttributes = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContent::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHTMLContent::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHTMLContent::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return NS_ERROR_FAILURE;
}
nsresult nsHTMLContent::GetListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
if (nsnull != mListenerManager) {
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);;
}
else {
nsIEventListenerManager* l = new nsEventListenerManager();
if (nsnull == l) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (NS_OK == l->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult)) {
mListenerManager = l;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
}
nsresult nsHTMLContent::AddEventListener(nsIDOMEventListener *aListener, const nsIID& aIID)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
manager->AddEventListener(aListener, aIID);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult nsHTMLContent::RemoveEventListener(nsIDOMEventListener *aListener, const nsIID& aIID)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
manager->RemoveEventListener(aListener, aIID);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult nsHTMLContent::HandleDOMEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsIDOMEvent* aDOMEvent,
nsEventStatus& aEventStatus)
{
//Capturing stage
//Local handling stage
if (nsnull != mListenerManager) {
mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aEventStatus);
}
//Bubbling stage
if (mParent != nsnull) {
return mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aEventStatus);
}
return NS_OK;
}
// XXX i18n: this is wrong (?) because we need to know the outgoing
// character set (I think)
void
nsHTMLContent::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('"');
}