2001-09-25 05:32:19 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2006-02-01 01:19:46 +03:00
|
|
|
/* vim: set ts=2 sw=2 et tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2006-03-31 12:00:42 +04:00
|
|
|
/*
|
|
|
|
* nsIContentSerializer implementation that can be used with an
|
|
|
|
* nsIDocumentEncoder to convert an HTML (not XHTML!) DOM to an HTML
|
|
|
|
* string that could be parsed into more or less the original DOM.
|
|
|
|
*/
|
|
|
|
|
2000-09-10 06:17:54 +04:00
|
|
|
#include "nsHTMLContentSerializer.h"
|
|
|
|
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIContent.h"
|
2000-09-10 10:44:06 +04:00
|
|
|
#include "nsIDocument.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2000-09-10 06:17:54 +04:00
|
|
|
#include "nsString.h"
|
2002-04-30 00:29:54 +04:00
|
|
|
#include "nsUnicharUtils.h"
|
2000-09-10 10:44:06 +04:00
|
|
|
#include "nsXPIDLString.h"
|
2000-09-10 06:17:54 +04:00
|
|
|
#include "nsIServiceManager.h"
|
2000-09-10 10:44:06 +04:00
|
|
|
#include "nsIDocumentEncoder.h"
|
2007-01-30 03:06:41 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2000-09-10 10:44:06 +04:00
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsNetUtil.h"
|
2000-10-12 02:50:14 +04:00
|
|
|
#include "nsEscape.h"
|
2001-05-11 04:27:03 +04:00
|
|
|
#include "nsITextToSubURI.h"
|
2002-05-15 22:55:21 +04:00
|
|
|
#include "nsCRT.h"
|
2002-11-22 15:20:05 +03:00
|
|
|
#include "nsIParserService.h"
|
|
|
|
#include "nsContentUtils.h"
|
2003-05-23 09:59:56 +04:00
|
|
|
#include "nsLWBrkCIID.h"
|
2006-02-01 01:19:46 +03:00
|
|
|
#include "nsIScriptElement.h"
|
2005-12-29 00:52:39 +03:00
|
|
|
#include "nsAttrName.h"
|
2010-11-07 01:49:26 +03:00
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIEditor.h"
|
2011-03-25 18:03:33 +03:00
|
|
|
#include "nsIHTMLEditor.h"
|
2010-10-23 01:25:22 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2011-08-01 11:48:24 +04:00
|
|
|
#include "nsParserConstants.h"
|
2010-10-23 01:25:22 +04:00
|
|
|
|
|
|
|
using namespace mozilla::dom;
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2000-09-10 23:36:22 +04:00
|
|
|
nsresult NS_NewHTMLContentSerializer(nsIContentSerializer** aSerializer)
|
|
|
|
{
|
|
|
|
nsHTMLContentSerializer* it = new nsHTMLContentSerializer();
|
|
|
|
if (!it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
2002-12-11 17:24:49 +03:00
|
|
|
return CallQueryInterface(it, aSerializer);
|
2000-09-10 23:36:22 +04:00
|
|
|
}
|
|
|
|
|
2000-09-10 06:17:54 +04:00
|
|
|
nsHTMLContentSerializer::nsHTMLContentSerializer()
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsHTMLSerializer = true;
|
2000-09-10 06:17:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLContentSerializer::~nsHTMLContentSerializer()
|
|
|
|
{
|
2003-05-23 09:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-13 22:41:16 +04:00
|
|
|
NS_IMETHODIMP
|
2010-05-04 17:19:54 +04:00
|
|
|
nsHTMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
|
2002-08-13 22:41:16 +04:00
|
|
|
nsAString& aStr)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2000-09-10 10:44:06 +04:00
|
|
|
void
|
2009-09-01 18:31:05 +04:00
|
|
|
nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
|
2010-05-04 17:19:54 +04:00
|
|
|
nsIContent *aOriginalElement,
|
2009-09-01 18:31:05 +04:00
|
|
|
nsAString& aTagPrefix,
|
|
|
|
const nsAString& aTagNamespaceURI,
|
|
|
|
nsIAtom* aTagName,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aNamespace,
|
2009-09-01 18:31:05 +04:00
|
|
|
nsAString& aStr)
|
2000-09-10 10:44:06 +04:00
|
|
|
{
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t count = aContent->GetAttrCount();
|
2009-06-29 02:44:22 +04:00
|
|
|
if (!count)
|
|
|
|
return;
|
|
|
|
|
2000-09-10 10:44:06 +04:00
|
|
|
nsresult rv;
|
2010-03-08 18:45:00 +03:00
|
|
|
nsAutoString valueStr;
|
2003-07-14 11:37:39 +04:00
|
|
|
NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t index = count; index > 0;) {
|
2009-12-23 11:32:39 +03:00
|
|
|
--index;
|
2005-12-29 00:52:39 +03:00
|
|
|
const nsAttrName* name = aContent->GetAttrNameAt(index);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t namespaceID = name->NamespaceID();
|
2005-12-29 00:52:39 +03:00
|
|
|
nsIAtom* attrName = name->LocalName();
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2002-04-13 11:47:21 +04:00
|
|
|
// Filter out any attribute starting with [-|_]moz
|
2010-03-08 18:45:00 +03:00
|
|
|
nsDependentAtomString attrNameStr(attrName);
|
|
|
|
if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
|
|
|
|
StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
|
2000-09-10 10:44:06 +04:00
|
|
|
continue;
|
2003-03-21 23:13:08 +03:00
|
|
|
}
|
2001-08-17 12:14:14 +04:00
|
|
|
aContent->GetAttr(namespaceID, attrName, valueStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Filter out special case of <br type="_moz"> or <br _moz*>,
|
|
|
|
// used by the editor. Bug 16988. Yuck.
|
|
|
|
//
|
2011-05-09 10:48:46 +04:00
|
|
|
if (aTagName == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML &&
|
|
|
|
attrName == nsGkAtoms::type && namespaceID == kNameSpaceID_None &&
|
2003-07-14 11:37:39 +04:00
|
|
|
StringBeginsWith(valueStr, _mozStr)) {
|
2000-09-10 10:44:06 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (mIsCopying && mIsFirstChildOfOL &&
|
|
|
|
aTagName == nsGkAtoms::li && aNamespace == kNameSpaceID_XHTML &&
|
|
|
|
attrName == nsGkAtoms::value && namespaceID == kNameSpaceID_None){
|
2002-03-12 11:21:51 +03:00
|
|
|
// This is handled separately in SerializeLIValueAttribute()
|
|
|
|
continue;
|
|
|
|
}
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
|
2001-08-01 17:39:46 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (((attrName == nsGkAtoms::href &&
|
|
|
|
(namespaceID == kNameSpaceID_None ||
|
|
|
|
namespaceID == kNameSpaceID_XLink)) ||
|
|
|
|
(attrName == nsGkAtoms::src && namespaceID == kNameSpaceID_None))) {
|
2001-05-11 04:27:03 +04:00
|
|
|
// Make all links absolute when converting only the selection:
|
|
|
|
if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
|
|
|
|
// Would be nice to handle OBJECT and APPLET tags,
|
|
|
|
// but that gets more complicated since we have to
|
|
|
|
// search the tag list for CODEBASE as well.
|
|
|
|
// For now, just leave them relative.
|
2004-01-10 02:54:21 +03:00
|
|
|
nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
|
2003-10-22 10:09:48 +04:00
|
|
|
if (uri) {
|
|
|
|
nsAutoString absURI;
|
|
|
|
rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
valueStr = absURI;
|
2000-09-10 23:36:22 +04:00
|
|
|
}
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
|
|
|
}
|
2001-05-11 04:27:03 +04:00
|
|
|
// Need to escape URI.
|
|
|
|
nsAutoString tempURI(valueStr);
|
2009-04-25 13:00:14 +04:00
|
|
|
if (!isJS && NS_FAILED(EscapeURI(aContent, tempURI, valueStr)))
|
2001-05-11 04:27:03 +04:00
|
|
|
valueStr = tempURI;
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
2002-05-28 16:34:48 +04:00
|
|
|
|
2009-09-28 11:59:52 +04:00
|
|
|
if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&
|
2011-05-09 10:48:46 +04:00
|
|
|
aNamespace == kNameSpaceID_XHTML && attrName == nsGkAtoms::content
|
|
|
|
&& namespaceID == kNameSpaceID_None) {
|
2007-12-29 03:23:58 +03:00
|
|
|
// If we're serializing a <meta http-equiv="content-type">,
|
|
|
|
// use the proper value, rather than what's in the document.
|
|
|
|
nsAutoString header;
|
|
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
|
|
|
|
if (header.LowerCaseEqualsLiteral("content-type")) {
|
|
|
|
valueStr = NS_LITERAL_STRING("text/html; charset=") +
|
|
|
|
NS_ConvertASCIItoUTF16(mCharset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-08 18:45:00 +03:00
|
|
|
nsDependentAtomString nameStr(attrName);
|
2011-05-09 10:48:46 +04:00
|
|
|
nsAutoString prefix;
|
|
|
|
if (namespaceID == kNameSpaceID_XML) {
|
2014-05-26 22:54:10 +04:00
|
|
|
prefix.AssignLiteral(MOZ_UTF16("xml"));
|
2011-05-09 10:48:46 +04:00
|
|
|
} else if (namespaceID == kNameSpaceID_XLink) {
|
2014-05-26 22:54:10 +04:00
|
|
|
prefix.AssignLiteral(MOZ_UTF16("xlink"));
|
2011-05-09 10:48:46 +04:00
|
|
|
}
|
2001-08-01 17:39:46 +04:00
|
|
|
|
2002-05-28 16:34:48 +04:00
|
|
|
// Expand shorthand attribute.
|
2011-05-09 10:48:46 +04:00
|
|
|
if (aNamespace == kNameSpaceID_XHTML &&
|
|
|
|
namespaceID == kNameSpaceID_None &&
|
|
|
|
IsShorthandAttr(attrName, aTagName) &&
|
|
|
|
valueStr.IsEmpty()) {
|
2002-05-28 16:34:48 +04:00
|
|
|
valueStr = nameStr;
|
|
|
|
}
|
2011-05-09 10:48:46 +04:00
|
|
|
SerializeAttr(prefix, nameStr, valueStr, aStr, !isJS);
|
2000-09-10 06:17:54 +04:00
|
|
|
}
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2010-10-23 01:25:22 +04:00
|
|
|
nsHTMLContentSerializer::AppendElementStart(Element* aElement,
|
|
|
|
Element* aOriginalElement,
|
2002-03-24 02:54:46 +03:00
|
|
|
nsAString& aStr)
|
2000-09-10 10:44:06 +04:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aElement);
|
2006-02-01 01:19:46 +03:00
|
|
|
|
2010-05-04 17:19:54 +04:00
|
|
|
nsIContent* content = aElement;
|
2006-02-01 01:19:46 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool forceFormat = false;
|
2009-04-25 13:00:14 +04:00
|
|
|
if (!CheckElementStart(content, forceFormat, aStr)) {
|
2002-04-11 01:25:15 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-04-25 13:00:14 +04:00
|
|
|
nsIAtom *name = content->Tag();
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t ns = content->GetNameSpaceID();
|
2010-11-07 01:49:26 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
|
2009-04-25 13:00:14 +04:00
|
|
|
if (mColPos && lineBreakBeforeOpen) {
|
|
|
|
AppendNewLineToString(aStr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MaybeAddNewlineForRootNode(aStr);
|
|
|
|
}
|
|
|
|
if (!mColPos) {
|
|
|
|
AppendIndentation(aStr);
|
|
|
|
}
|
|
|
|
else if (mAddSpace) {
|
2014-01-04 19:02:17 +04:00
|
|
|
AppendToString(char16_t(' '), aStr);
|
2011-10-17 18:59:28 +04:00
|
|
|
mAddSpace = false;
|
2009-04-25 13:00:14 +04:00
|
|
|
}
|
2002-10-15 02:07:48 +04:00
|
|
|
}
|
|
|
|
else if (mAddSpace) {
|
2014-01-04 19:02:17 +04:00
|
|
|
AppendToString(char16_t(' '), aStr);
|
2011-10-17 18:59:28 +04:00
|
|
|
mAddSpace = false;
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
2003-10-24 02:24:21 +04:00
|
|
|
else {
|
2009-04-25 13:00:14 +04:00
|
|
|
MaybeAddNewlineForRootNode(aStr);
|
2003-10-24 02:24:21 +04:00
|
|
|
}
|
2009-04-25 13:00:14 +04:00
|
|
|
// Always reset to avoid false newlines in case MaybeAddNewlineForRootNode wasn't
|
2003-10-24 02:24:21 +04:00
|
|
|
// called
|
2011-10-17 18:59:28 +04:00
|
|
|
mAddNewlineForRootNode = false;
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2000-09-12 00:55:46 +04:00
|
|
|
AppendToString(kLessThan, aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2010-03-08 18:45:00 +03:00
|
|
|
AppendToString(nsDependentAtomString(name), aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2009-04-25 13:00:14 +04:00
|
|
|
MaybeEnterInPreContent(content);
|
|
|
|
|
|
|
|
// for block elements, we increase the indentation
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel())
|
2009-04-25 13:00:14 +04:00
|
|
|
IncrIndentation(name);
|
|
|
|
|
2002-03-12 11:21:51 +03:00
|
|
|
// Need to keep track of OL and LI elements in order to get ordinal number
|
|
|
|
// for the LI.
|
2011-05-09 10:48:46 +04:00
|
|
|
if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML){
|
2002-03-12 11:21:51 +03:00
|
|
|
// We are copying and current node is an OL;
|
2009-01-23 12:02:09 +03:00
|
|
|
// Store its start attribute value in olState->startVal.
|
2002-03-12 11:21:51 +03:00
|
|
|
nsAutoString start;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startAttrVal = 0;
|
2010-05-04 17:19:54 +04:00
|
|
|
|
|
|
|
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
|
2002-03-12 11:21:51 +03:00
|
|
|
if (!start.IsEmpty()){
|
2012-07-27 17:59:29 +04:00
|
|
|
nsresult rv = NS_OK;
|
2002-03-12 11:21:51 +03:00
|
|
|
startAttrVal = start.ToInteger(&rv);
|
|
|
|
//If OL has "start" attribute, first LI element has to start with that value
|
|
|
|
//Therefore subtracting 1 as all the LI elements are incrementing it before using it;
|
|
|
|
//In failure of ToInteger(), default StartAttrValue to 0.
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
startAttrVal--;
|
|
|
|
else
|
|
|
|
startAttrVal = 0;
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mOLStateStack.AppendElement(olState(startAttrVal, true));
|
2002-03-12 11:21:51 +03:00
|
|
|
}
|
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (mIsCopying && name == nsGkAtoms::li && ns == kNameSpaceID_XHTML) {
|
2006-04-07 00:55:25 +04:00
|
|
|
mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
|
2002-03-12 11:21:51 +03:00
|
|
|
if (mIsFirstChildOfOL){
|
|
|
|
// If OL is parent of this LI, serialize attributes in different manner.
|
|
|
|
SerializeLIValueAttribute(aElement, aStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Even LI passed above have to go through this
|
|
|
|
// for serializing attributes other than "value".
|
2009-04-25 13:00:14 +04:00
|
|
|
nsAutoString dummyPrefix;
|
2011-05-09 10:48:46 +04:00
|
|
|
SerializeHTMLAttributes(content,
|
|
|
|
aOriginalElement,
|
|
|
|
dummyPrefix,
|
|
|
|
EmptyString(),
|
|
|
|
name,
|
|
|
|
ns,
|
|
|
|
aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2000-09-12 00:55:46 +04:00
|
|
|
AppendToString(kGreaterThan, aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (ns == kNameSpaceID_XHTML &&
|
|
|
|
(name == nsGkAtoms::script ||
|
|
|
|
name == nsGkAtoms::style ||
|
|
|
|
name == nsGkAtoms::noscript ||
|
|
|
|
name == nsGkAtoms::noframes)) {
|
2009-04-25 13:00:14 +04:00
|
|
|
++mDisableEntityEncoding;
|
2000-10-13 15:06:05 +04:00
|
|
|
}
|
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel() &&
|
|
|
|
LineBreakAfterOpen(ns, name)) {
|
2009-04-25 13:00:14 +04:00
|
|
|
AppendNewLineToString(aStr);
|
2007-06-17 15:41:03 +04:00
|
|
|
}
|
2007-05-13 20:44:06 +04:00
|
|
|
|
2009-04-25 13:00:14 +04:00
|
|
|
AfterElementStart(content, aOriginalElement, aStr);
|
|
|
|
|
2000-09-10 06:17:54 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2010-10-23 01:25:22 +04:00
|
|
|
nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
|
2002-03-24 02:54:46 +03:00
|
|
|
nsAString& aStr)
|
2000-09-10 06:17:54 +04:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aElement);
|
|
|
|
|
2010-05-04 17:19:54 +04:00
|
|
|
nsIContent* content = aElement;
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2003-11-19 04:20:56 +03:00
|
|
|
nsIAtom *name = content->Tag();
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t ns = content->GetNameSpaceID();
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (ns == kNameSpaceID_XHTML &&
|
|
|
|
(name == nsGkAtoms::script ||
|
|
|
|
name == nsGkAtoms::style ||
|
|
|
|
name == nsGkAtoms::noscript ||
|
|
|
|
name == nsGkAtoms::noframes)) {
|
2009-04-25 13:00:14 +04:00
|
|
|
--mDisableEntityEncoding;
|
|
|
|
}
|
|
|
|
|
2012-04-24 10:06:11 +04:00
|
|
|
bool forceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
|
|
|
|
content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
|
2009-04-25 13:00:14 +04:00
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
|
2009-04-25 13:00:14 +04:00
|
|
|
DecrIndentation(name);
|
|
|
|
}
|
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
if (name == nsGkAtoms::script) {
|
2006-02-01 01:19:46 +03:00
|
|
|
nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aElement);
|
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if (ShouldMaintainPreLevel() && script && script->IsMalformed()) {
|
2006-02-01 01:19:46 +03:00
|
|
|
// We're looking at a malformed script tag. This means that the end tag
|
|
|
|
// was missing in the source. Imitate that here by not serializing the end
|
|
|
|
// tag.
|
2015-01-12 19:41:10 +03:00
|
|
|
--PreLevel();
|
2006-02-01 01:19:46 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2011-05-09 10:48:46 +04:00
|
|
|
else if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML) {
|
2009-04-25 13:00:14 +04:00
|
|
|
NS_ASSERTION((!mOLStateStack.IsEmpty()), "Cannot have an empty OL Stack");
|
2002-03-12 11:21:51 +03:00
|
|
|
/* Though at this point we must always have an state to be deleted as all
|
|
|
|
the OL opening tags are supposed to push an olState object to the stack*/
|
2009-03-20 11:15:35 +03:00
|
|
|
if (!mOLStateStack.IsEmpty()) {
|
|
|
|
mOLStateStack.RemoveElementAt(mOLStateStack.Length() -1);
|
2002-03-12 11:21:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (ns == kNameSpaceID_XHTML) {
|
|
|
|
nsIParserService* parserService = nsContentUtils::GetParserService();
|
2000-10-13 15:06:05 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (parserService) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isContainer;
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
parserService->
|
|
|
|
IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
|
|
|
|
isContainer);
|
|
|
|
if (!isContainer) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2000-09-10 06:17:54 +04:00
|
|
|
}
|
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
|
2009-04-25 13:00:14 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool lineBreakBeforeClose = LineBreakBeforeClose(ns, name);
|
2009-04-25 13:00:14 +04:00
|
|
|
|
|
|
|
if (mColPos && lineBreakBeforeClose) {
|
|
|
|
AppendNewLineToString(aStr);
|
|
|
|
}
|
|
|
|
if (!mColPos) {
|
|
|
|
AppendIndentation(aStr);
|
|
|
|
}
|
|
|
|
else if (mAddSpace) {
|
2014-01-04 19:02:17 +04:00
|
|
|
AppendToString(char16_t(' '), aStr);
|
2011-10-17 18:59:28 +04:00
|
|
|
mAddSpace = false;
|
2009-04-25 13:00:14 +04:00
|
|
|
}
|
2002-10-15 02:07:48 +04:00
|
|
|
}
|
|
|
|
else if (mAddSpace) {
|
2014-01-04 19:02:17 +04:00
|
|
|
AppendToString(char16_t(' '), aStr);
|
2011-10-17 18:59:28 +04:00
|
|
|
mAddSpace = false;
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
|
|
|
|
2000-09-12 00:55:46 +04:00
|
|
|
AppendToString(kEndTag, aStr);
|
2010-03-08 18:45:00 +03:00
|
|
|
AppendToString(nsDependentAtomString(name), aStr);
|
2000-09-12 00:55:46 +04:00
|
|
|
AppendToString(kGreaterThan, aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
|
2009-04-25 13:00:14 +04:00
|
|
|
MaybeLeaveFromPreContent(content);
|
|
|
|
|
2015-01-12 19:41:10 +03:00
|
|
|
if ((mDoFormat || forceFormat)&& !mDoRaw && !PreLevel()
|
|
|
|
&& LineBreakAfterClose(ns, name)) {
|
2009-04-25 13:00:14 +04:00
|
|
|
AppendNewLineToString(aStr);
|
2000-09-10 10:44:06 +04:00
|
|
|
}
|
2003-10-24 02:24:21 +04:00
|
|
|
else {
|
2009-04-25 13:00:14 +04:00
|
|
|
MaybeFlagNewlineForRootNode(aElement);
|
2003-10-24 02:24:21 +04:00
|
|
|
}
|
2000-09-10 06:17:54 +04:00
|
|
|
|
2011-05-09 10:48:46 +04:00
|
|
|
if (name == nsGkAtoms::body && ns == kNameSpaceID_XHTML) {
|
2008-10-22 00:30:09 +04:00
|
|
|
--mInBody;
|
|
|
|
}
|
|
|
|
|
2000-09-10 06:17:54 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-03-18 19:07:32 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
static const uint16_t kValNBSP = 160;
|
2010-03-18 19:07:32 +03:00
|
|
|
static const char* kEntities[] = {
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "&", nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
"<", nullptr, ">", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
2010-10-17 18:15:54 +04:00
|
|
|
" "
|
2010-03-18 19:07:32 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char* kAttrEntities[] = {
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, """, nullptr, nullptr, nullptr, "&", nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
"<", nullptr, ">", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
2010-10-17 18:15:54 +04:00
|
|
|
" "
|
2010-03-18 19:07:32 +03:00
|
|
|
};
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t FindNextBasicEntity(const nsAString& aStr,
|
|
|
|
const uint32_t aLen,
|
|
|
|
uint32_t aIndex,
|
2010-10-17 18:15:54 +04:00
|
|
|
const char** aEntityTable,
|
|
|
|
const char** aEntity)
|
|
|
|
{
|
|
|
|
for (; aIndex < aLen; ++aIndex) {
|
|
|
|
// for each character in this chunk, check if it
|
|
|
|
// needs to be replaced
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t val = aStr[aIndex];
|
2010-10-17 18:15:54 +04:00
|
|
|
if (val <= kValNBSP && aEntityTable[val]) {
|
|
|
|
*aEntity = aEntityTable[val];
|
|
|
|
return aIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return aIndex;
|
|
|
|
}
|
|
|
|
|
2010-03-18 19:07:32 +03:00
|
|
|
void
|
|
|
|
nsHTMLContentSerializer::AppendAndTranslateEntities(const nsAString& aStr,
|
|
|
|
nsAString& aOutputStr)
|
|
|
|
{
|
|
|
|
if (mBodyOnly && !mInBody) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDisableEntityEncoding) {
|
|
|
|
aOutputStr.Append(aStr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool nonBasicEntities =
|
2010-10-17 18:15:54 +04:00
|
|
|
!!(mFlags & (nsIDocumentEncoder::OutputEncodeLatin1Entities |
|
|
|
|
nsIDocumentEncoder::OutputEncodeHTMLEntities |
|
|
|
|
nsIDocumentEncoder::OutputEncodeW3CEntities));
|
|
|
|
|
|
|
|
if (!nonBasicEntities &&
|
|
|
|
(mFlags & (nsIDocumentEncoder::OutputEncodeBasicEntities))) {
|
|
|
|
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t start = 0;
|
|
|
|
const uint32_t len = aStr.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
2012-07-30 18:20:58 +04:00
|
|
|
const char* entity = nullptr;
|
2010-10-17 18:15:54 +04:00
|
|
|
i = FindNextBasicEntity(aStr, len, i, entityTable, &entity);
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t normalTextLen = i - start;
|
2010-10-17 18:15:54 +04:00
|
|
|
if (normalTextLen) {
|
|
|
|
aOutputStr.Append(Substring(aStr, start, normalTextLen));
|
|
|
|
}
|
|
|
|
if (entity) {
|
|
|
|
aOutputStr.AppendASCII(entity);
|
|
|
|
start = i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (nonBasicEntities) {
|
2010-03-18 19:07:32 +03:00
|
|
|
nsIParserService* parserService = nsContentUtils::GetParserService();
|
|
|
|
|
|
|
|
if (!parserService) {
|
|
|
|
NS_ERROR("Can't get parser service");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
nsReadingIterator<char16_t> done_reading;
|
2010-03-18 19:07:32 +03:00
|
|
|
aStr.EndReading(done_reading);
|
|
|
|
|
|
|
|
// for each chunk of |aString|...
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t advanceLength = 0;
|
2014-01-04 19:02:17 +04:00
|
|
|
nsReadingIterator<char16_t> iter;
|
2010-03-18 19:07:32 +03:00
|
|
|
|
|
|
|
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString entityReplacement;
|
2010-03-18 19:07:32 +03:00
|
|
|
|
|
|
|
for (aStr.BeginReading(iter);
|
|
|
|
iter != done_reading;
|
2012-08-22 19:56:38 +04:00
|
|
|
iter.advance(int32_t(advanceLength))) {
|
|
|
|
uint32_t fragmentLength = iter.size_forward();
|
|
|
|
uint32_t lengthReplaced = 0; // the number of UTF-16 codepoints
|
2010-03-18 19:07:32 +03:00
|
|
|
// replaced by a particular entity
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t* c = iter.get();
|
|
|
|
const char16_t* fragmentStart = c;
|
|
|
|
const char16_t* fragmentEnd = c + fragmentLength;
|
2012-07-30 18:20:58 +04:00
|
|
|
const char* entityText = nullptr;
|
|
|
|
const char* fullConstEntityText = nullptr;
|
|
|
|
char* fullEntityText = nullptr;
|
2010-03-18 19:07:32 +03:00
|
|
|
|
|
|
|
advanceLength = 0;
|
|
|
|
// for each character in this chunk, check if it
|
|
|
|
// needs to be replaced
|
|
|
|
for (; c < fragmentEnd; c++, advanceLength++) {
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t val = *c;
|
2010-10-17 18:15:54 +04:00
|
|
|
if (val <= kValNBSP && entityTable[val]) {
|
2010-05-14 14:18:27 +04:00
|
|
|
fullConstEntityText = entityTable[val];
|
2010-03-18 19:07:32 +03:00
|
|
|
break;
|
|
|
|
} else if (val > 127 &&
|
|
|
|
((val < 256 &&
|
|
|
|
mFlags & nsIDocumentEncoder::OutputEncodeLatin1Entities) ||
|
|
|
|
mFlags & nsIDocumentEncoder::OutputEncodeHTMLEntities)) {
|
2010-05-14 14:18:27 +04:00
|
|
|
entityReplacement.Truncate();
|
2010-03-18 19:07:32 +03:00
|
|
|
parserService->HTMLConvertUnicodeToEntity(val, entityReplacement);
|
|
|
|
|
|
|
|
if (!entityReplacement.IsEmpty()) {
|
|
|
|
entityText = entityReplacement.get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (val > 127 &&
|
|
|
|
mFlags & nsIDocumentEncoder::OutputEncodeW3CEntities &&
|
|
|
|
mEntityConverter) {
|
|
|
|
if (NS_IS_HIGH_SURROGATE(val) &&
|
|
|
|
c + 1 < fragmentEnd &&
|
|
|
|
NS_IS_LOW_SURROGATE(*(c + 1))) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t valUTF32 = SURROGATE_TO_UCS4(val, *(++c));
|
2010-03-18 19:07:32 +03:00
|
|
|
if (NS_SUCCEEDED(mEntityConverter->ConvertUTF32ToEntity(valUTF32,
|
|
|
|
nsIEntityConverter::entityW3C, &fullEntityText))) {
|
|
|
|
lengthReplaced = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
advanceLength++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_SUCCEEDED(mEntityConverter->ConvertToEntity(val,
|
|
|
|
nsIEntityConverter::entityW3C,
|
|
|
|
&fullEntityText))) {
|
|
|
|
lengthReplaced = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aOutputStr.Append(fragmentStart, advanceLength);
|
|
|
|
if (entityText) {
|
2014-01-04 19:02:17 +04:00
|
|
|
aOutputStr.Append(char16_t('&'));
|
2010-03-18 19:07:32 +03:00
|
|
|
AppendASCIItoUTF16(entityText, aOutputStr);
|
2014-01-04 19:02:17 +04:00
|
|
|
aOutputStr.Append(char16_t(';'));
|
2010-03-18 19:07:32 +03:00
|
|
|
advanceLength++;
|
|
|
|
}
|
2010-05-14 14:18:27 +04:00
|
|
|
else if (fullConstEntityText) {
|
|
|
|
aOutputStr.AppendASCII(fullConstEntityText);
|
|
|
|
++advanceLength;
|
|
|
|
}
|
2010-03-18 19:07:32 +03:00
|
|
|
// if it comes from nsIEntityConverter, it already has '&' and ';'
|
|
|
|
else if (fullEntityText) {
|
|
|
|
AppendASCIItoUTF16(fullEntityText, aOutputStr);
|
|
|
|
nsMemory::Free(fullEntityText);
|
|
|
|
advanceLength += lengthReplaced;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nsXMLContentSerializer::AppendAndTranslateEntities(aStr, aOutputStr);
|
|
|
|
}
|
|
|
|
}
|