Mozilla/mozilla/layout/html/document/src/nsHTMLFragmentContentSink.cpp
vidur%netscape.com dd84ad6b9c possibly temporary sink implementation to build a document fragment.
git-svn-id: svn://10.0.0.236/trunk@33209 18797224-902f-48f8-a5cc-f745e15eee43
1999-05-29 01:29:01 +00:00

446 lines
10 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 "nsCOMPtr.h"
#include "nsIHTMLContentSink.h"
#include "nsIParser.h"
#include "nsIHTMLContent.h"
#include "nsIHTMLContentContainer.h"
#include "nsHTMLTokens.h"
#include "nsHTMLEntities.h"
#include "nsHTMLParts.h"
//
// XXX THIS IS TEMPORARY CODE
// There's a considerable amount of copied code from the
// regular nsHTMLContentSink. All of it will be factored
// at some pointe really soon!
//
class nsHTMLFragmentContentSink : public nsIHTMLContentSink {
public:
nsHTMLFragmentContentSink();
virtual ~nsHTMLFragmentContentSink();
// nsISupports
NS_DECL_ISUPPORTS
// nsIContentSink
NS_IMETHOD WillBuildModel(void);
NS_IMETHOD DidBuildModel(PRInt32 aQualityLevel);
NS_IMETHOD WillInterrupt(void);
NS_IMETHOD WillResume(void);
NS_IMETHOD SetParser(nsIParser* aParser);
// nsIHTMLContentSink
NS_IMETHOD BeginContext(PRInt32 aID);
NS_IMETHOD EndContext(PRInt32 aID);
NS_IMETHOD SetTitle(const nsString& aValue);
NS_IMETHOD OpenHTML(const nsIParserNode& aNode);
NS_IMETHOD CloseHTML(const nsIParserNode& aNode);
NS_IMETHOD OpenHead(const nsIParserNode& aNode);
NS_IMETHOD CloseHead(const nsIParserNode& aNode);
NS_IMETHOD OpenBody(const nsIParserNode& aNode);
NS_IMETHOD CloseBody(const nsIParserNode& aNode);
NS_IMETHOD OpenForm(const nsIParserNode& aNode);
NS_IMETHOD CloseForm(const nsIParserNode& aNode);
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD OpenMap(const nsIParserNode& aNode);
NS_IMETHOD CloseMap(const nsIParserNode& aNode);
NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
NS_IMETHOD CloseContainer(const nsIParserNode& aNode);
NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
NS_IMETHOD NotifyError(const nsParserError* aError);
NS_IMETHOD AddComment(const nsIParserNode& aNode);
NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode);
NS_IMETHOD DoFragment(PRBool aFlag);
nsIContent* GetCurrentContent();
PRInt32 PushContent(nsIContent *aContent);
nsIContent* PopContent();
nsresult AddAttributes(const nsIParserNode& aNode,
nsIContent* aContent,
PRBool aIsHTML);
nsresult AddText(const nsString& aString);
nsresult FlushText(PRBool aCreateTextNode=PR_TRUE,
PRBool* aDidFlush=nsnull);
PRBool mHitSentinel;
nsIContent* mRoot;
nsIParser* mParser;
nsIDOMHTMLFormElement* mCurrentForm;
nsIHTMLContent* mCurrentMap;
nsVoidArray* mContentStack;
PRUnichar* mText;
PRInt32 mTextLength;
PRInt32 mTextSize;
};
nsHTMLFragmentContentSink::nsHTMLFragmentContentSink()
{
mHitSentinel = PR_FALSE;
mRoot = nsnull;
mParser = nsnull;
mCurrentForm = nsnull;
mCurrentMap = nsnull;
mContentStack = nsnull;
mText = nsnull;
mTextLength = 0;
mTextSize = 0;
}
nsHTMLFragmentContentSink::~nsHTMLFragmentContentSink()
{
NS_IF_RELEASE(mRoot);
NS_IF_RELEASE(mParser);
NS_IF_RELEASE(mCurrentForm);
NS_IF_RELEASE(mCurrentMap);
if (nsnull != mContentStack) {
// there shouldn't be anything here except in an error condition
PRInt32 index = mContentStack->Count();
while (0 < index--) {
nsIContent* content = (nsIContent*)mContentStack->ElementAt(index);
NS_RELEASE(content);
}
delete mContentStack;
}
if (nsnull != mText) {
PR_FREEIF(mText);
}
}
NS_IMPL_ISUPPORTS(nsHTMLFragmentContentSink, kIHTMLContentSinkIID)
NS_IMETHODIMP
nsHTMLFragmentContentSink::WillBuildModel(void)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::DidBuildModel(PRInt32 aQualityLevel)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::WillInterrupt(void)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::WillResume(void)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::SetParser(nsIParser* aParser)
{
NS_IF_RELEASE(mParser);
mParser = aParser;
NS_IF_ADDREF(mParser);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::BeginContext(PRInt32 aID)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::EndContext(PRInt32 aID)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::SetTitle(const nsString& aValue)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenHTML(const nsIParserNode& aNode)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseHTML(const nsIParserNode& aNode)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenHead(const nsIParserNode& aNode)
{
// XXX Not likely to get a head in the paste
return OpenContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseHead(const nsIParserNode& aNode)
{
return CloseContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenBody(const nsIParserNode& aNode)
{
return OpenContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseBody(const nsIParserNode& aNode)
{
return CloseContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenForm(const nsIParserNode& aNode)
{
return OpenContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseForm(const nsIParserNode& aNode)
{
return CloseContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenFrameset(const nsIParserNode& aNode)
{
return OpenContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseFrameset(const nsIParserNode& aNode)
{
return CloseContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenMap(const nsIParserNode& aNode)
{
return OpenContainer(aNode);
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseMap(const nsIParserNode& aNode)
{
return CloseContainer(aNode);
}
static char* kSentinelStr = "endnote";
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode)
{
nsAutoString tag;
tag = aNode.GetText();
if (tag.EqualsIgnoreCase(kSentinelStr)) {
mHitSentinel = PR_TRUE;
}
else if (mHitSentinel) {
FlushText();
nsIHTMLContent *content = nsnull;
result = NS_CreateHTMLElement(&content, tag);
if (NS_OK == result) {
result = AddAttributes(aNode, content);
if (NS_OK == result) {
nsIContent *parent = GetCurrentContent();
if (nsnull == parent) {
parent = mRoot;
}
parent->AppendChildTo(content, PR_FALSE);
PushContent(content);
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseContainer(const nsIParserNode& aNode)
{
if (mHitSentinel && (nsnull != GetCurrentContent()) {
nsIContent content;
FlushText();
content = PopContent();
NS_RELEASE(content);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::AddLeaf(const nsIParserNode& aNode)
{
nsresult result = NS_OK;
nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
switch (nodeType) {
case eToken_start:
{
FlushText();
// Create new leaf content object
nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
nsIHTMLContent* content;
result = NS_CreateHTMLElement(&content, tag);
if (NS_OK == result) {
result = AddAttributes(aNode, content);
if (NS_OK == result) {
nsIContent *parent = GetCurrentContent();
if (nsnull == parent) {
parent = mRoot;
}
parent->AppendChildTo(content, PR_FALSE);
}
NS_RELEASE(content);
}
}
break;
case eToken_text:
case eToken_whitespace:
case eToken_newline:
result = AddText(aNode.GetText());
break;
case eToken_entity:
{
nsAutoString tmp;
PRInt32 unicode = aNode.TranslateToUnicodeStr(tmp);
if (unicode < 0) {
result = AddText(aNode.GetText());
}
else {
result = AddText(tmp);
}
}
break;
}
return result;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::NotifyError(const nsParserError* aError)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::AddComment(const nsIParserNode& aNode)
{
nsIContent *comment;
nsIDOMComment *domComment;
nsresult result = NS_OK;
FlushText();
result = NS_NewCommentNode(&comment);
if (NS_OK == result) {
result = comment->QueryInterface(kIDOMCommentIID,
(void **)&domComment);
if (NS_OK == result) {
domComment->AppendData(aNode.GetText());
NS_RELEASE(domComment);
nsIContent *parent = GetCurrentContent();
if (nsnull == parent) {
parent = mRoot;
}
parent->AppendChildTo(comment, PR_FALSE);
}
NS_RELEASE(comment);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::AddProcessingInstruction(const nsIParserNode& aNode)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::DoFragment(PRBool aFlag)
{
return NS_OK;
}
nsIContent*
nsHTMLFragmentContentSink::GetCurrentContent()
{
if (nsnull != mContentStack) {
PRInt32 index = mContentStack->Count() - 1;
return (nsIContent *)mContentStack->ElementAt(index);
}
return nsnull;
}
PRInt32
nsHTMLFragmentContentSink::PushContent(nsIContent *aContent)
{
if (nsnull == mContentStack) {
mContentStack = new nsVoidArray();
}
mContentStack->AppendElement((void *)aContent);
return mContentStack->Count();
}
nsIContent*
nsHTMLFragmentContentSink::PopContent()
{
nsIContent* content = nsnull;
if (nsnull != mContentStack) {
PRInt32 index = mContentStack->Count() - 1;
content = (nsIContent *)mContentStack->ElementAt(index);
mContentStack->RemoveElementAt(index);
}
return content;
}