LCOV - code coverage report
Current view: top level - dom/base - nsXHTMLContentSerializer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 420 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * nsIContentSerializer implementation that can be used with an
       9             :  * nsIDocumentEncoder to convert an XHTML (not HTML!) DOM to an XHTML
      10             :  * string that could be parsed into more or less the original DOM.
      11             :  */
      12             : 
      13             : #include "nsXHTMLContentSerializer.h"
      14             : 
      15             : #include "nsIDOMElement.h"
      16             : #include "nsIContent.h"
      17             : #include "nsIDocument.h"
      18             : #include "nsNameSpaceManager.h"
      19             : #include "nsString.h"
      20             : #include "nsUnicharUtils.h"
      21             : #include "nsXPIDLString.h"
      22             : #include "nsIServiceManager.h"
      23             : #include "nsIDocumentEncoder.h"
      24             : #include "nsGkAtoms.h"
      25             : #include "nsIURI.h"
      26             : #include "nsNetUtil.h"
      27             : #include "nsEscape.h"
      28             : #include "nsCRT.h"
      29             : #include "nsIParserService.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsLWBrkCIID.h"
      32             : #include "nsIScriptElement.h"
      33             : #include "nsStubMutationObserver.h"
      34             : #include "nsAttrName.h"
      35             : #include "nsComputedDOMStyle.h"
      36             : #include "mozilla/dom/Element.h"
      37             : 
      38             : static const int32_t kLongLineLen = 128;
      39             : 
      40             : #define kXMLNS "xmlns"
      41             : 
      42             : nsresult
      43           0 : NS_NewXHTMLContentSerializer(nsIContentSerializer** aSerializer)
      44             : {
      45           0 :   RefPtr<nsXHTMLContentSerializer> it = new nsXHTMLContentSerializer();
      46           0 :   it.forget(aSerializer);
      47           0 :   return NS_OK;
      48             : }
      49             : 
      50           0 : nsXHTMLContentSerializer::nsXHTMLContentSerializer()
      51           0 :   : mIsHTMLSerializer(false)
      52             : {
      53           0 : }
      54             : 
      55           0 : nsXHTMLContentSerializer::~nsXHTMLContentSerializer()
      56             : {
      57           0 :   NS_ASSERTION(mOLStateStack.IsEmpty(), "Expected OL State stack to be empty");
      58           0 : }
      59             : 
      60             : NS_IMETHODIMP
      61           0 : nsXHTMLContentSerializer::Init(uint32_t aFlags,
      62             :                                uint32_t aWrapColumn,
      63             :                                const mozilla::Encoding* aEncoding,
      64             :                                bool aIsCopying,
      65             :                                bool aRewriteEncodingDeclaration,
      66             :                                bool* aNeedsPreformatScanning)
      67             : {
      68             :   // The previous version of the HTML serializer did implicit wrapping
      69             :   // when there is no flags, so we keep wrapping in order to keep
      70             :   // compatibility with the existing calling code
      71             :   // XXXLJ perhaps should we remove this default settings later ?
      72           0 :   if (aFlags & nsIDocumentEncoder::OutputFormatted ) {
      73           0 :       aFlags = aFlags | nsIDocumentEncoder::OutputWrap;
      74             :   }
      75             : 
      76             :   nsresult rv;
      77           0 :   rv = nsXMLContentSerializer::Init(
      78           0 :     aFlags, aWrapColumn, aEncoding, aIsCopying, aRewriteEncodingDeclaration, aNeedsPreformatScanning);
      79           0 :   NS_ENSURE_SUCCESS(rv, rv);
      80             : 
      81           0 :   mRewriteEncodingDeclaration = aRewriteEncodingDeclaration;
      82           0 :   mIsCopying = aIsCopying;
      83           0 :   mIsFirstChildOfOL = false;
      84           0 :   mInBody = 0;
      85           0 :   mDisableEntityEncoding = 0;
      86           0 :   mBodyOnly = (mFlags & nsIDocumentEncoder::OutputBodyOnly) ? true
      87             :                                                             : false;
      88             : 
      89             :   // set up entity converter if we are going to need it
      90           0 :   if (mFlags & nsIDocumentEncoder::OutputEncodeW3CEntities) {
      91           0 :     mEntityConverter = do_CreateInstance(NS_ENTITYCONVERTER_CONTRACTID);
      92             :   }
      93           0 :   return NS_OK;
      94             : }
      95             : 
      96             : 
      97             : // See if the string has any lines longer than longLineLen:
      98             : // if so, we presume formatting is wonky (e.g. the node has been edited)
      99             : // and we'd better rewrap the whole text node.
     100             : bool
     101           0 : nsXHTMLContentSerializer::HasLongLines(const nsString& text, int32_t& aLastNewlineOffset)
     102             : {
     103           0 :   uint32_t start=0;
     104           0 :   uint32_t theLen = text.Length();
     105           0 :   bool rv = false;
     106           0 :   aLastNewlineOffset = kNotFound;
     107           0 :   for (start = 0; start < theLen; ) {
     108           0 :     int32_t eol = text.FindChar('\n', start);
     109           0 :     if (eol < 0) {
     110           0 :       eol = text.Length();
     111             :     }
     112             :     else {
     113           0 :       aLastNewlineOffset = eol;
     114             :     }
     115           0 :     if (int32_t(eol - start) > kLongLineLen)
     116           0 :       rv = true;
     117           0 :     start = eol + 1;
     118             :   }
     119           0 :   return rv;
     120             : }
     121             : 
     122             : NS_IMETHODIMP
     123           0 : nsXHTMLContentSerializer::AppendText(nsIContent* aText,
     124             :                                      int32_t aStartOffset,
     125             :                                      int32_t aEndOffset,
     126             :                                      nsAString& aStr)
     127             : {
     128           0 :   NS_ENSURE_ARG(aText);
     129             : 
     130           0 :   nsAutoString data;
     131             :   nsresult rv;
     132             : 
     133           0 :   rv = AppendTextData(aText, aStartOffset, aEndOffset, data, true);
     134           0 :   if (NS_FAILED(rv))
     135           0 :     return NS_ERROR_FAILURE;
     136             : 
     137           0 :   if (mDoRaw || PreLevel() > 0) {
     138           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     139             :   }
     140           0 :   else if (mDoFormat) {
     141           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     142             :   }
     143           0 :   else if (mDoWrap) {
     144           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     145             :   }
     146             :   else {
     147           0 :     int32_t lastNewlineOffset = kNotFound;
     148           0 :     if (HasLongLines(data, lastNewlineOffset)) {
     149             :       // We have long lines, rewrap
     150           0 :       mDoWrap = true;
     151           0 :       bool result = AppendToStringWrapped(data, aStr);
     152           0 :       mDoWrap = false;
     153           0 :       NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
     154             :     }
     155             :     else {
     156           0 :       NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     157             :     }
     158             :   }
     159             : 
     160           0 :   return NS_OK;
     161             : }
     162             : 
     163             : bool
     164           0 : nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
     165             :                                               nsIContent *aOriginalElement,
     166             :                                               nsAString& aTagPrefix,
     167             :                                               const nsAString& aTagNamespaceURI,
     168             :                                               nsIAtom* aTagName,
     169             :                                               nsAString& aStr,
     170             :                                               uint32_t aSkipAttr,
     171             :                                               bool aAddNSAttr)
     172             : {
     173             :   nsresult rv;
     174             :   uint32_t index, count;
     175           0 :   nsAutoString prefixStr, uriStr, valueStr;
     176           0 :   nsAutoString xmlnsStr;
     177           0 :   xmlnsStr.AssignLiteral(kXMLNS);
     178             : 
     179           0 :   int32_t contentNamespaceID = aContent->GetNameSpaceID();
     180             : 
     181             :   // this method is not called by nsHTMLContentSerializer
     182             :   // so we don't have to check HTML element, just XHTML
     183             : 
     184           0 :   if (mIsCopying && kNameSpaceID_XHTML == contentNamespaceID) {
     185             : 
     186             :     // Need to keep track of OL and LI elements in order to get ordinal number
     187             :     // for the LI.
     188           0 :     if (aTagName == nsGkAtoms::ol) {
     189             :       // We are copying and current node is an OL;
     190             :       // Store its start attribute value in olState->startVal.
     191           0 :       nsAutoString start;
     192           0 :       int32_t startAttrVal = 0;
     193           0 :       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
     194           0 :       if (!start.IsEmpty()) {
     195           0 :         nsresult rv = NS_OK;
     196           0 :         startAttrVal = start.ToInteger(&rv);
     197             :         //If OL has "start" attribute, first LI element has to start with that value
     198             :         //Therefore subtracting 1 as all the LI elements are incrementing it before using it;
     199             :         //In failure of ToInteger(), default StartAttrValue to 0.
     200           0 :         if (NS_SUCCEEDED(rv))
     201           0 :           --startAttrVal;
     202             :         else
     203           0 :           startAttrVal = 0;
     204             :       }
     205           0 :       olState state (startAttrVal, true);
     206           0 :       mOLStateStack.AppendElement(state);
     207             :     }
     208           0 :     else if (aTagName == nsGkAtoms::li) {
     209           0 :       mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
     210           0 :       if (mIsFirstChildOfOL) {
     211             :         // If OL is parent of this LI, serialize attributes in different manner.
     212           0 :         NS_ENSURE_TRUE(SerializeLIValueAttribute(aContent, aStr), false);
     213             :       }
     214             :     }
     215             :   }
     216             : 
     217             :   // If we had to add a new namespace declaration, serialize
     218             :   // and push it on the namespace stack
     219           0 :   if (aAddNSAttr) {
     220           0 :     if (aTagPrefix.IsEmpty()) {
     221             :       // Serialize default namespace decl
     222           0 :       NS_ENSURE_TRUE(SerializeAttr(EmptyString(), xmlnsStr,
     223             :                                    aTagNamespaceURI,
     224             :                                    aStr, true), false);
     225             :     } else {
     226             :       // Serialize namespace decl
     227           0 :       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, aTagPrefix,
     228             :                                    aTagNamespaceURI,
     229             :                                    aStr, true), false);
     230             :     }
     231           0 :     PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
     232             :   }
     233             : 
     234           0 :   NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
     235             : 
     236           0 :   count = aContent->GetAttrCount();
     237             : 
     238             :   // Now serialize each of the attributes
     239             :   // XXX Unfortunately we need a namespace manager to get
     240             :   // attribute URIs.
     241           0 :   for (index = 0; index < count; index++) {
     242             : 
     243           0 :     if (aSkipAttr == index) {
     244           0 :         continue;
     245             :     }
     246             : 
     247           0 :     mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
     248           0 :     const nsAttrName* name = info.mName;
     249             : 
     250           0 :     int32_t namespaceID = name->NamespaceID();
     251           0 :     nsIAtom* attrName = name->LocalName();
     252           0 :     nsIAtom* attrPrefix = name->GetPrefix();
     253             : 
     254             :     // Filter out any attribute starting with [-|_]moz
     255           0 :     nsDependentAtomString attrNameStr(attrName);
     256           0 :     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
     257           0 :         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
     258           0 :       continue;
     259             :     }
     260             : 
     261           0 :     if (attrPrefix) {
     262           0 :       attrPrefix->ToString(prefixStr);
     263             :     }
     264             :     else {
     265           0 :       prefixStr.Truncate();
     266             :     }
     267             : 
     268           0 :     bool addNSAttr = false;
     269           0 :     if (kNameSpaceID_XMLNS != namespaceID) {
     270           0 :       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
     271           0 :       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     272             :     }
     273             : 
     274           0 :     info.mValue->ToString(valueStr);
     275             : 
     276           0 :     nsDependentAtomString nameStr(attrName);
     277           0 :     bool isJS = false;
     278             : 
     279           0 :     if (kNameSpaceID_XHTML == contentNamespaceID) {
     280             :       //
     281             :       // Filter out special case of <br type="_moz"> or <br _moz*>,
     282             :       // used by the editor.  Bug 16988.  Yuck.
     283             :       //
     284           0 :       if (namespaceID == kNameSpaceID_None && aTagName == nsGkAtoms::br && attrName == nsGkAtoms::type
     285           0 :           && StringBeginsWith(valueStr, _mozStr)) {
     286           0 :         continue;
     287             :       }
     288             : 
     289           0 :       if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li)
     290           0 :           && (attrName == nsGkAtoms::value)) {
     291             :         // This is handled separately in SerializeLIValueAttribute()
     292           0 :         continue;
     293             :       }
     294             : 
     295           0 :       isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
     296             : 
     297           0 :       if (namespaceID == kNameSpaceID_None &&
     298           0 :           ((attrName == nsGkAtoms::href) ||
     299           0 :           (attrName == nsGkAtoms::src))) {
     300             :         // Make all links absolute when converting only the selection:
     301           0 :         if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
     302             :           // Would be nice to handle OBJECT and APPLET tags,
     303             :           // but that gets more complicated since we have to
     304             :           // search the tag list for CODEBASE as well.
     305             :           // For now, just leave them relative.
     306           0 :           nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
     307           0 :           if (uri) {
     308           0 :             nsAutoString absURI;
     309           0 :             rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
     310           0 :             if (NS_SUCCEEDED(rv)) {
     311           0 :               valueStr = absURI;
     312             :             }
     313             :           }
     314             :         }
     315             :       }
     316             : 
     317           0 :       if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&
     318           0 :           attrName == nsGkAtoms::content) {
     319             :         // If we're serializing a <meta http-equiv="content-type">,
     320             :         // use the proper value, rather than what's in the document.
     321           0 :         nsAutoString header;
     322           0 :         aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     323           0 :         if (header.LowerCaseEqualsLiteral("content-type")) {
     324           0 :           valueStr = NS_LITERAL_STRING("text/html; charset=") +
     325           0 :             NS_ConvertASCIItoUTF16(mCharset);
     326             :         }
     327             :       }
     328             : 
     329             :       // Expand shorthand attribute.
     330           0 :       if (namespaceID == kNameSpaceID_None && IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) {
     331           0 :         valueStr = nameStr;
     332             :       }
     333             :     }
     334             :     else {
     335           0 :       isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
     336             :     }
     337             : 
     338           0 :     NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
     339             : 
     340           0 :     if (addNSAttr) {
     341           0 :       NS_ASSERTION(!prefixStr.IsEmpty(),
     342             :                    "Namespaced attributes must have a prefix");
     343           0 :       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false);
     344           0 :       PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement);
     345             :     }
     346             :   }
     347             : 
     348           0 :   return true;
     349             : }
     350             : 
     351             : bool
     352           0 : nsXHTMLContentSerializer::AfterElementStart(nsIContent* aContent,
     353             :                                             nsIContent* aOriginalElement,
     354             :                                             nsAString& aStr)
     355             : {
     356           0 :   if (mRewriteEncodingDeclaration &&
     357           0 :       aContent->IsHTMLElement(nsGkAtoms::head)) {
     358             : 
     359             :     // Check if there already are any content-type meta children.
     360             :     // If there are, they will be modified to use the correct charset.
     361             :     // If there aren't, we'll insert one here.
     362           0 :     bool hasMeta = false;
     363           0 :     for (nsIContent* child = aContent->GetFirstChild();
     364           0 :          child;
     365           0 :          child = child->GetNextSibling()) {
     366           0 :       if (child->IsHTMLElement(nsGkAtoms::meta) &&
     367           0 :           child->HasAttr(kNameSpaceID_None, nsGkAtoms::content)) {
     368           0 :         nsAutoString header;
     369           0 :         child->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     370             : 
     371           0 :         if (header.LowerCaseEqualsLiteral("content-type")) {
     372           0 :           hasMeta = true;
     373           0 :           break;
     374             :         }
     375             :       }
     376             :     }
     377             : 
     378           0 :     if (!hasMeta) {
     379           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aStr), false);
     380           0 :       if (mDoFormat) {
     381           0 :         NS_ENSURE_TRUE(AppendIndentation(aStr), false);
     382             :       }
     383           0 :       NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""), aStr), false);
     384           0 :       NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr), false);
     385           0 :       NS_ENSURE_TRUE(AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr), false);
     386           0 :       if (mIsHTMLSerializer) {
     387           0 :         NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("\">"), aStr), false);
     388             :       } else {
     389           0 :         NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("\" />"), aStr), false);
     390             :       }
     391             :     }
     392             :   }
     393             : 
     394           0 :   return true;
     395             : }
     396             : 
     397             : void
     398           0 : nsXHTMLContentSerializer::AfterElementEnd(nsIContent * aContent,
     399             :                                           nsAString& aStr)
     400             : {
     401           0 :   NS_ASSERTION(!mIsHTMLSerializer, "nsHTMLContentSerializer shouldn't call this method !");
     402             : 
     403             :   // this method is not called by nsHTMLContentSerializer
     404             :   // so we don't have to check HTML element, just XHTML
     405           0 :   if (aContent->IsHTMLElement(nsGkAtoms::body)) {
     406           0 :     --mInBody;
     407             :   }
     408           0 : }
     409             : 
     410             : 
     411             : NS_IMETHODIMP
     412           0 : nsXHTMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
     413             :                                               nsAString& aStr)
     414             : {
     415           0 :   if (!mBodyOnly)
     416           0 :     return nsXMLContentSerializer::AppendDocumentStart(aDocument, aStr);
     417             : 
     418           0 :   return NS_OK;
     419             : }
     420             : 
     421             : bool
     422           0 : nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
     423             :                                             bool & aForceFormat,
     424             :                                             nsAString& aStr,
     425             :                                             nsresult& aResult)
     426             : {
     427           0 :   aResult = NS_OK;
     428             : 
     429             :   // The _moz_dirty attribute is emitted by the editor to
     430             :   // indicate that this element should be pretty printed
     431             :   // even if we're not in pretty printing mode
     432           0 :   aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
     433           0 :                  aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
     434             : 
     435           0 :   if (aContent->IsHTMLElement(nsGkAtoms::br) &&
     436           0 :       (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre) &&
     437           0 :       PreLevel() > 0) {
     438           0 :     aResult = AppendNewLineToString(aStr) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     439           0 :     return false;
     440             :   }
     441             : 
     442           0 :   if (aContent->IsHTMLElement(nsGkAtoms::body)) {
     443           0 :     ++mInBody;
     444             :   }
     445             : 
     446           0 :   return true;
     447             : }
     448             : 
     449             : bool
     450           0 : nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement,
     451             :                                           bool& aForceFormat,
     452             :                                           nsAString& aStr)
     453             : {
     454           0 :   NS_ASSERTION(!mIsHTMLSerializer, "nsHTMLContentSerializer shouldn't call this method !");
     455             : 
     456           0 :   aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
     457           0 :                  aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
     458             : 
     459           0 :   if (mIsCopying && aElement->IsHTMLElement(nsGkAtoms::ol)) {
     460           0 :     NS_ASSERTION((!mOLStateStack.IsEmpty()), "Cannot have an empty OL Stack");
     461             :     /* Though at this point we must always have an state to be deleted as all
     462             :        the OL opening tags are supposed to push an olState object to the stack*/
     463           0 :     if (!mOLStateStack.IsEmpty()) {
     464           0 :         mOLStateStack.RemoveElementAt(mOLStateStack.Length() -1);
     465             :     }
     466             :   }
     467             : 
     468             :   bool dummyFormat;
     469           0 :   return nsXMLContentSerializer::CheckElementEnd(aElement, dummyFormat, aStr);
     470             : }
     471             : 
     472             : bool
     473           0 : nsXHTMLContentSerializer::AppendAndTranslateEntities(const nsAString& aStr,
     474             :                                                      nsAString& aOutputStr)
     475             : {
     476           0 :   if (mBodyOnly && !mInBody) {
     477           0 :     return true;
     478             :   }
     479             : 
     480           0 :   if (mDisableEntityEncoding) {
     481           0 :     return aOutputStr.Append(aStr, mozilla::fallible);
     482             :   }
     483             : 
     484           0 :   return nsXMLContentSerializer::AppendAndTranslateEntities(aStr, aOutputStr);
     485             : }
     486             : 
     487             : bool
     488           0 : nsXHTMLContentSerializer::IsShorthandAttr(const nsIAtom* aAttrName,
     489             :                                           const nsIAtom* aElementName)
     490             : {
     491             :   // checked
     492           0 :   if ((aAttrName == nsGkAtoms::checked) &&
     493           0 :       (aElementName == nsGkAtoms::input)) {
     494           0 :     return true;
     495             :   }
     496             : 
     497             :   // compact
     498           0 :   if ((aAttrName == nsGkAtoms::compact) &&
     499           0 :       (aElementName == nsGkAtoms::dir ||
     500           0 :        aElementName == nsGkAtoms::dl ||
     501           0 :        aElementName == nsGkAtoms::menu ||
     502           0 :        aElementName == nsGkAtoms::ol ||
     503           0 :        aElementName == nsGkAtoms::ul)) {
     504           0 :     return true;
     505             :   }
     506             : 
     507             :   // declare
     508           0 :   if ((aAttrName == nsGkAtoms::declare) &&
     509           0 :       (aElementName == nsGkAtoms::object)) {
     510           0 :     return true;
     511             :   }
     512             : 
     513             :   // defer
     514           0 :   if ((aAttrName == nsGkAtoms::defer) &&
     515           0 :       (aElementName == nsGkAtoms::script)) {
     516           0 :     return true;
     517             :   }
     518             : 
     519             :   // disabled
     520           0 :   if ((aAttrName == nsGkAtoms::disabled) &&
     521           0 :       (aElementName == nsGkAtoms::button ||
     522           0 :        aElementName == nsGkAtoms::input ||
     523           0 :        aElementName == nsGkAtoms::optgroup ||
     524           0 :        aElementName == nsGkAtoms::option ||
     525           0 :        aElementName == nsGkAtoms::select ||
     526           0 :        aElementName == nsGkAtoms::textarea)) {
     527           0 :     return true;
     528             :   }
     529             : 
     530             :   // ismap
     531           0 :   if ((aAttrName == nsGkAtoms::ismap) &&
     532           0 :       (aElementName == nsGkAtoms::img ||
     533           0 :        aElementName == nsGkAtoms::input)) {
     534           0 :     return true;
     535             :   }
     536             : 
     537             :   // multiple
     538           0 :   if ((aAttrName == nsGkAtoms::multiple) &&
     539           0 :       (aElementName == nsGkAtoms::select)) {
     540           0 :     return true;
     541             :   }
     542             : 
     543             :   // noresize
     544           0 :   if ((aAttrName == nsGkAtoms::noresize) &&
     545           0 :       (aElementName == nsGkAtoms::frame)) {
     546           0 :     return true;
     547             :   }
     548             : 
     549             :   // noshade
     550           0 :   if ((aAttrName == nsGkAtoms::noshade) &&
     551           0 :       (aElementName == nsGkAtoms::hr)) {
     552           0 :     return true;
     553             :   }
     554             : 
     555             :   // nowrap
     556           0 :   if ((aAttrName == nsGkAtoms::nowrap) &&
     557           0 :       (aElementName == nsGkAtoms::td ||
     558           0 :        aElementName == nsGkAtoms::th)) {
     559           0 :     return true;
     560             :   }
     561             : 
     562             :   // readonly
     563           0 :   if ((aAttrName == nsGkAtoms::readonly) &&
     564           0 :       (aElementName == nsGkAtoms::input ||
     565           0 :        aElementName == nsGkAtoms::textarea)) {
     566           0 :     return true;
     567             :   }
     568             : 
     569             :   // selected
     570           0 :   if ((aAttrName == nsGkAtoms::selected) &&
     571           0 :       (aElementName == nsGkAtoms::option)) {
     572           0 :     return true;
     573             :   }
     574             : 
     575             :   // autoplay and controls
     576           0 :   if ((aElementName == nsGkAtoms::video || aElementName == nsGkAtoms::audio) &&
     577           0 :     (aAttrName == nsGkAtoms::autoplay || aAttrName == nsGkAtoms::muted ||
     578           0 :      aAttrName == nsGkAtoms::controls)) {
     579           0 :     return true;
     580             :   }
     581             : 
     582           0 :   return false;
     583             : }
     584             : 
     585             : bool
     586           0 : nsXHTMLContentSerializer::LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName)
     587             : {
     588             : 
     589           0 :   if (aNamespaceID != kNameSpaceID_XHTML) {
     590           0 :     return mAddSpace;
     591             :   }
     592             : 
     593           0 :   if (aName == nsGkAtoms::title ||
     594           0 :       aName == nsGkAtoms::meta  ||
     595           0 :       aName == nsGkAtoms::link  ||
     596           0 :       aName == nsGkAtoms::style ||
     597           0 :       aName == nsGkAtoms::select ||
     598           0 :       aName == nsGkAtoms::option ||
     599           0 :       aName == nsGkAtoms::script ||
     600           0 :       aName == nsGkAtoms::html) {
     601           0 :     return true;
     602             :   }
     603             :   else {
     604           0 :     nsIParserService* parserService = nsContentUtils::GetParserService();
     605             : 
     606           0 :     if (parserService) {
     607             :       bool res;
     608             :       parserService->
     609           0 :         IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
     610           0 :       return res;
     611             :     }
     612             :   }
     613             : 
     614           0 :   return mAddSpace;
     615             : }
     616             : 
     617             : bool
     618           0 : nsXHTMLContentSerializer::LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName)
     619             : {
     620             : 
     621           0 :   if (aNamespaceID != kNameSpaceID_XHTML) {
     622           0 :     return false;
     623             :   }
     624             : 
     625           0 :   if ((aName == nsGkAtoms::html) ||
     626           0 :       (aName == nsGkAtoms::head) ||
     627           0 :       (aName == nsGkAtoms::body) ||
     628           0 :       (aName == nsGkAtoms::ul) ||
     629           0 :       (aName == nsGkAtoms::ol) ||
     630           0 :       (aName == nsGkAtoms::dl) ||
     631           0 :       (aName == nsGkAtoms::table) ||
     632           0 :       (aName == nsGkAtoms::tbody) ||
     633           0 :       (aName == nsGkAtoms::tr) ||
     634           0 :       (aName == nsGkAtoms::br) ||
     635           0 :       (aName == nsGkAtoms::meta) ||
     636           0 :       (aName == nsGkAtoms::link) ||
     637           0 :       (aName == nsGkAtoms::script) ||
     638           0 :       (aName == nsGkAtoms::select) ||
     639           0 :       (aName == nsGkAtoms::map) ||
     640           0 :       (aName == nsGkAtoms::area) ||
     641           0 :       (aName == nsGkAtoms::style)) {
     642           0 :     return true;
     643             :   }
     644             : 
     645           0 :   return false;
     646             : }
     647             : 
     648             : bool
     649           0 : nsXHTMLContentSerializer::LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName)
     650             : {
     651             : 
     652           0 :   if (aNamespaceID != kNameSpaceID_XHTML) {
     653           0 :     return false;
     654             :   }
     655             : 
     656           0 :   if ((aName == nsGkAtoms::html) ||
     657           0 :       (aName == nsGkAtoms::head) ||
     658           0 :       (aName == nsGkAtoms::body) ||
     659           0 :       (aName == nsGkAtoms::ul) ||
     660           0 :       (aName == nsGkAtoms::ol) ||
     661           0 :       (aName == nsGkAtoms::dl) ||
     662           0 :       (aName == nsGkAtoms::select) ||
     663           0 :       (aName == nsGkAtoms::table) ||
     664           0 :       (aName == nsGkAtoms::tbody)) {
     665           0 :     return true;
     666             :   }
     667           0 :   return false;
     668             : }
     669             : 
     670             : bool
     671           0 : nsXHTMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName)
     672             : {
     673             : 
     674           0 :   if (aNamespaceID != kNameSpaceID_XHTML) {
     675           0 :     return false;
     676             :   }
     677             : 
     678           0 :   if ((aName == nsGkAtoms::html) ||
     679           0 :       (aName == nsGkAtoms::head) ||
     680           0 :       (aName == nsGkAtoms::body) ||
     681           0 :       (aName == nsGkAtoms::tr) ||
     682           0 :       (aName == nsGkAtoms::th) ||
     683           0 :       (aName == nsGkAtoms::td) ||
     684           0 :       (aName == nsGkAtoms::pre) ||
     685           0 :       (aName == nsGkAtoms::title) ||
     686           0 :       (aName == nsGkAtoms::li) ||
     687           0 :       (aName == nsGkAtoms::dt) ||
     688           0 :       (aName == nsGkAtoms::dd) ||
     689           0 :       (aName == nsGkAtoms::blockquote) ||
     690           0 :       (aName == nsGkAtoms::select) ||
     691           0 :       (aName == nsGkAtoms::option) ||
     692           0 :       (aName == nsGkAtoms::p) ||
     693           0 :       (aName == nsGkAtoms::map) ||
     694           0 :       (aName == nsGkAtoms::div)) {
     695           0 :     return true;
     696             :   }
     697             :   else {
     698           0 :     nsIParserService* parserService = nsContentUtils::GetParserService();
     699             : 
     700           0 :     if (parserService) {
     701             :       bool res;
     702             :       parserService->
     703           0 :         IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
     704           0 :       return res;
     705             :     }
     706             :   }
     707             : 
     708           0 :   return false;
     709             : }
     710             : 
     711             : 
     712             : void
     713           0 : nsXHTMLContentSerializer::MaybeEnterInPreContent(nsIContent* aNode)
     714             : {
     715           0 :   if (!ShouldMaintainPreLevel() ||
     716           0 :       !aNode->IsHTMLElement()) {
     717           0 :     return;
     718             :   }
     719             : 
     720           0 :   if (IsElementPreformatted(aNode) ||
     721           0 :       aNode->IsAnyOfHTMLElements(nsGkAtoms::script,
     722             :                                  nsGkAtoms::style,
     723             :                                  nsGkAtoms::noscript,
     724             :                                  nsGkAtoms::noframes)) {
     725           0 :     PreLevel()++;
     726             :   }
     727             : }
     728             : 
     729             : void
     730           0 : nsXHTMLContentSerializer::MaybeLeaveFromPreContent(nsIContent* aNode)
     731             : {
     732           0 :   if (!ShouldMaintainPreLevel() ||
     733           0 :       !aNode->IsHTMLElement()) {
     734           0 :     return;
     735             :   }
     736             : 
     737           0 :   if (IsElementPreformatted(aNode) ||
     738           0 :       aNode->IsAnyOfHTMLElements(nsGkAtoms::script,
     739             :                                  nsGkAtoms::style,
     740             :                                  nsGkAtoms::noscript,
     741             :                                  nsGkAtoms::noframes)) {
     742           0 :     --PreLevel();
     743             :   }
     744             : }
     745             : 
     746             : bool
     747           0 : nsXHTMLContentSerializer::IsElementPreformatted(nsIContent* aNode)
     748             : {
     749           0 :   MOZ_ASSERT(ShouldMaintainPreLevel(), "We should not be calling this needlessly");
     750             : 
     751           0 :   if (!aNode->IsElement()) {
     752           0 :     return false;
     753             :   }
     754             :   RefPtr<nsStyleContext> styleContext =
     755           0 :     nsComputedDOMStyle::GetStyleContextNoFlush(aNode->AsElement(),
     756           0 :                                                nullptr, nullptr);
     757           0 :   if (styleContext) {
     758           0 :     const nsStyleText* textStyle = styleContext->StyleText();
     759           0 :     return textStyle->WhiteSpaceOrNewlineIsSignificant();
     760             :   }
     761           0 :   return false;
     762             : }
     763             : 
     764             : bool
     765           0 : nsXHTMLContentSerializer::SerializeLIValueAttribute(nsIContent* aElement,
     766             :                                                     nsAString& aStr)
     767             : {
     768             :   // We are copying and we are at the "first" LI node of OL in selected range.
     769             :   // It may not be the first LI child of OL but it's first in the selected range.
     770             :   // Note that we get into this condition only once per a OL.
     771           0 :   bool found = false;
     772           0 :   nsCOMPtr<nsIDOMNode> currNode = do_QueryInterface(aElement);
     773           0 :   nsAutoString valueStr;
     774             : 
     775           0 :   olState state (0, false);
     776             : 
     777           0 :   if (!mOLStateStack.IsEmpty()) {
     778           0 :     state = mOLStateStack[mOLStateStack.Length()-1];
     779             :     // isFirstListItem should be true only before the serialization of the
     780             :     // first item in the list.
     781           0 :     state.isFirstListItem = false;
     782           0 :     mOLStateStack[mOLStateStack.Length()-1] = state;
     783             :   }
     784             : 
     785           0 :   int32_t startVal = state.startVal;
     786           0 :   int32_t offset = 0;
     787             : 
     788             :   // Traverse previous siblings until we find one with "value" attribute.
     789             :   // offset keeps track of how many previous siblings we had tocurrNode traverse.
     790           0 :   while (currNode && !found) {
     791           0 :     nsCOMPtr<nsIDOMElement> currElement = do_QueryInterface(currNode);
     792             :     // currElement may be null if it were a text node.
     793           0 :     if (currElement) {
     794           0 :       nsAutoString tagName;
     795           0 :       currElement->GetTagName(tagName);
     796           0 :       if (tagName.LowerCaseEqualsLiteral("li")) {
     797           0 :         currElement->GetAttribute(NS_LITERAL_STRING("value"), valueStr);
     798           0 :         if (valueStr.IsEmpty())
     799           0 :           offset++;
     800             :         else {
     801           0 :           found = true;
     802           0 :           nsresult rv = NS_OK;
     803           0 :           startVal = valueStr.ToInteger(&rv);
     804             :         }
     805             :       }
     806             :     }
     807           0 :     nsCOMPtr<nsIDOMNode> tmp;
     808           0 :     currNode->GetPreviousSibling(getter_AddRefs(tmp));
     809           0 :     currNode.swap(tmp);
     810             :   }
     811             :   // If LI was not having "value", Set the "value" attribute for it.
     812             :   // Note that We are at the first LI in the selected range of OL.
     813           0 :   if (offset == 0 && found) {
     814             :     // offset = 0 => LI itself has the value attribute and we did not need to traverse back.
     815             :     // Just serialize value attribute like other tags.
     816           0 :     NS_ENSURE_TRUE(SerializeAttr(EmptyString(), NS_LITERAL_STRING("value"),
     817             :                                  valueStr, aStr, false), false);
     818             :   }
     819           0 :   else if (offset == 1 && !found) {
     820             :     /*(offset = 1 && !found) means either LI is the first child node of OL
     821             :     and LI is not having "value" attribute.
     822             :     In that case we would not like to set "value" attribute to reduce the changes.
     823             :     */
     824             :     //do nothing...
     825             :   }
     826           0 :   else if (offset > 0) {
     827             :     // Set value attribute.
     828           0 :     nsAutoString valueStr;
     829             : 
     830             :     //As serializer needs to use this valueAttr we are creating here,
     831           0 :     valueStr.AppendInt(startVal + offset);
     832           0 :     NS_ENSURE_TRUE(SerializeAttr(EmptyString(), NS_LITERAL_STRING("value"),
     833             :                                  valueStr, aStr, false), false);
     834             :   }
     835             : 
     836           0 :   return true;
     837             : }
     838             : 
     839             : bool
     840           0 : nsXHTMLContentSerializer::IsFirstChildOfOL(nsIContent* aElement)
     841             : {
     842           0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
     843           0 :   nsAutoString parentName;
     844             : 
     845           0 :   nsCOMPtr<nsIDOMNode> parentNode;
     846           0 :   node->GetParentNode(getter_AddRefs(parentNode));
     847           0 :   if (parentNode)
     848           0 :     parentNode->GetNodeName(parentName);
     849             :   else
     850           0 :     return false;
     851             : 
     852           0 :   if (parentName.LowerCaseEqualsLiteral("ol")) {
     853             : 
     854           0 :     if (!mOLStateStack.IsEmpty()) {
     855           0 :       olState state = mOLStateStack[mOLStateStack.Length()-1];
     856           0 :       if (state.isFirstListItem)
     857           0 :         return true;
     858             :     }
     859             : 
     860           0 :     return false;
     861             :   }
     862             :   else
     863           0 :     return false;
     864             : }
     865             : 
     866             : bool
     867           0 : nsXHTMLContentSerializer::HasNoChildren(nsIContent * aContent) {
     868             : 
     869           0 :   for (nsIContent* child = aContent->GetFirstChild();
     870           0 :        child;
     871           0 :        child = child->GetNextSibling()) {
     872             : 
     873           0 :     if (!child->IsNodeOfType(nsINode::eTEXT))
     874           0 :       return false;
     875             : 
     876           0 :     if (child->TextLength())
     877           0 :       return false;
     878             :   }
     879             : 
     880           0 :   return true;
     881             : }

Generated by: LCOV version 1.13