LCOV - code coverage report
Current view: directory - content/html/document/src - nsHTMLContentSink.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 793 20 2.5 %
Date: 2012-06-02 Functions: 76 5 6.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set sw=2 ts=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   Peter Annema <disttsc@bart.nl>
      26                 :  *   Daniel Glazman <glazman@netscape.com>
      27                 :  *   Henri Sivonen <hsivonen@iki.fi>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "mozilla/Util.h"
      44                 : 
      45                 : #include "nsContentSink.h"
      46                 : #include "nsCOMPtr.h"
      47                 : #include "nsReadableUtils.h"
      48                 : #include "nsUnicharUtils.h"
      49                 : #include "nsIHTMLContentSink.h"
      50                 : #include "nsIInterfaceRequestor.h"
      51                 : #include "nsIInterfaceRequestorUtils.h"
      52                 : #include "nsIParser.h"
      53                 : #include "nsScriptLoader.h"
      54                 : #include "nsIURI.h"
      55                 : #include "nsNetUtil.h"
      56                 : #include "nsIContentViewer.h"
      57                 : #include "nsIMarkupDocumentViewer.h"
      58                 : #include "nsINodeInfo.h"
      59                 : #include "nsHTMLTokens.h"
      60                 : #include "nsIAppShell.h"
      61                 : #include "nsCRT.h"
      62                 : #include "prtime.h"
      63                 : #include "prlog.h"
      64                 : #include "nsNodeUtils.h"
      65                 : #include "nsIContent.h"
      66                 : #include "mozilla/dom/Element.h"
      67                 : #include "mozilla/Preferences.h"
      68                 : 
      69                 : #include "nsGenericHTMLElement.h"
      70                 : 
      71                 : #include "nsIDOMDocument.h"
      72                 : #include "nsIDOMDocumentType.h"
      73                 : #include "nsIScriptElement.h"
      74                 : 
      75                 : #include "nsIComponentManager.h"
      76                 : #include "nsIServiceManager.h"
      77                 : 
      78                 : #include "nsGkAtoms.h"
      79                 : #include "nsContentUtils.h"
      80                 : #include "nsIChannel.h"
      81                 : #include "nsIHttpChannel.h"
      82                 : #include "nsIDocShell.h"
      83                 : #include "nsIDocument.h"
      84                 : #include "nsStubDocumentObserver.h"
      85                 : #include "nsIHTMLDocument.h"
      86                 : #include "nsINameSpaceManager.h"
      87                 : #include "nsIDOMHTMLMapElement.h"
      88                 : #include "nsICookieService.h"
      89                 : #include "nsTArray.h"
      90                 : #include "nsIScriptSecurityManager.h"
      91                 : #include "nsIPrincipal.h"
      92                 : #include "nsTextFragment.h"
      93                 : #include "nsIScriptGlobalObject.h"
      94                 : #include "nsIScriptGlobalObjectOwner.h"
      95                 : 
      96                 : #include "nsIParserService.h"
      97                 : 
      98                 : #include "nsIStyleSheetLinkingElement.h"
      99                 : #include "nsITimer.h"
     100                 : #include "nsDOMError.h"
     101                 : #include "nsContentPolicyUtils.h"
     102                 : #include "nsIScriptContext.h"
     103                 : #include "nsStyleLinkElement.h"
     104                 : 
     105                 : #include "nsReadableUtils.h"
     106                 : #include "nsWeakReference.h" // nsHTMLElementFactory supports weak references
     107                 : #include "nsIPrompt.h"
     108                 : #include "nsLayoutCID.h"
     109                 : #include "nsIDocShellTreeItem.h"
     110                 : 
     111                 : #include "nsEscape.h"
     112                 : #include "nsIElementObserver.h"
     113                 : #include "nsNodeInfoManager.h"
     114                 : #include "nsContentCreatorFunctions.h"
     115                 : #include "mozAutoDocUpdate.h"
     116                 : 
     117                 : using namespace mozilla;
     118                 : using namespace mozilla::dom;
     119                 : 
     120                 : #ifdef NS_DEBUG
     121                 : static PRLogModuleInfo* gSinkLogModuleInfo;
     122                 : 
     123                 : #define SINK_TRACE_NODE(_bit, _msg, _tag, _sp, _obj) \
     124                 :   _obj->SinkTraceNode(_bit, _msg, _tag, _sp, this)
     125                 : 
     126                 : #else
     127                 : #define SINK_TRACE_NODE(_bit, _msg, _tag, _sp, _obj)
     128                 : #endif
     129                 : 
     130                 : //----------------------------------------------------------------------
     131                 : 
     132                 : typedef nsGenericHTMLElement*
     133                 :   (*contentCreatorCallback)(already_AddRefed<nsINodeInfo>,
     134                 :                             FromParser aFromParser);
     135                 : 
     136                 : nsGenericHTMLElement*
     137               0 : NS_NewHTMLNOTUSEDElement(already_AddRefed<nsINodeInfo> aNodeInfo,
     138                 :                          FromParser aFromParser)
     139                 : {
     140               0 :   NS_NOTREACHED("The element ctor should never be called");
     141               0 :   return nsnull;
     142                 : }
     143                 : 
     144                 : #define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element,
     145                 : #define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement,
     146                 : #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
     147                 : static const contentCreatorCallback sContentCreatorCallbacks[] = {
     148                 :   NS_NewHTMLUnknownElement,
     149                 : #include "nsHTMLTagList.h"
     150                 : #undef HTML_TAG
     151                 : #undef HTML_HTMLELEMENT_TAG
     152                 : #undef HTML_OTHER
     153                 :   NS_NewHTMLUnknownElement
     154                 : };
     155                 : 
     156                 : class SinkContext;
     157                 : class HTMLContentSink;
     158                 : 
     159                 : class HTMLContentSink : public nsContentSink,
     160                 : #ifdef DEBUG
     161                 :                         public nsIDebugDumpContent,
     162                 : #endif
     163                 :                         public nsIHTMLContentSink
     164                 : {
     165                 : public:
     166                 :   friend class SinkContext;
     167                 : 
     168                 :   HTMLContentSink();
     169                 :   virtual ~HTMLContentSink();
     170                 : 
     171               0 :   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
     172                 : 
     173                 :   nsresult Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer,
     174                 :                 nsIChannel* aChannel);
     175                 : 
     176                 :   // nsISupports
     177                 :   NS_DECL_ISUPPORTS_INHERITED
     178            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)
     179                 : 
     180                 :   // nsIContentSink
     181                 :   NS_IMETHOD WillParse(void);
     182                 :   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
     183                 :   NS_IMETHOD DidBuildModel(bool aTerminated);
     184                 :   NS_IMETHOD WillInterrupt(void);
     185                 :   NS_IMETHOD WillResume(void);
     186                 :   NS_IMETHOD SetParser(nsParserBase* aParser);
     187                 :   virtual void FlushPendingNotifications(mozFlushType aType);
     188                 :   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
     189                 :   virtual nsISupports *GetTarget();
     190                 :   virtual bool IsScriptExecuting();
     191                 : 
     192                 :   // nsIHTMLContentSink
     193               0 :   virtual bool IsAboutBlank() { return true; }
     194                 :   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
     195                 :   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
     196                 :   NS_IMETHOD CloseMalformedContainer(const nsHTMLTag aTag);
     197                 :   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
     198                 :   NS_IMETHOD DidProcessTokens(void);
     199                 :   NS_IMETHOD WillProcessAToken(void);
     200                 :   NS_IMETHOD DidProcessAToken(void);
     201                 :   NS_IMETHOD BeginContext(PRInt32 aID);
     202                 :   NS_IMETHOD EndContext(PRInt32 aID);
     203                 :   NS_IMETHOD OpenHead();
     204                 :   NS_IMETHOD IsEnabled(PRInt32 aTag, bool* aReturn);
     205                 : 
     206                 : #ifdef DEBUG
     207                 :   // nsIDebugDumpContent
     208                 :   NS_IMETHOD DumpContentModel();
     209                 : #endif
     210                 : 
     211                 : protected:
     212                 :   // If aCheckIfPresent is true, will only set an attribute in cases
     213                 :   // when it's not already set.
     214                 :   nsresult AddAttributes(const nsIParserNode& aNode, nsIContent* aContent,
     215                 :                          bool aNotify = false,
     216                 :                          bool aCheckIfPresent = false);
     217                 :   already_AddRefed<nsGenericHTMLElement>
     218                 :   CreateContentObject(const nsIParserNode& aNode, nsHTMLTag aNodeType);
     219                 : 
     220                 : #ifdef NS_DEBUG
     221                 :   void SinkTraceNode(PRUint32 aBit,
     222                 :                      const char* aMsg,
     223                 :                      const nsHTMLTag aTag,
     224                 :                      PRInt32 aStackPos,
     225                 :                      void* aThis);
     226                 : #endif
     227                 : 
     228                 :   nsCOMPtr<nsIHTMLDocument> mHTMLDocument;
     229                 : 
     230                 :   // The maximum length of a text run
     231                 :   PRInt32 mMaxTextRun;
     232                 : 
     233                 :   nsRefPtr<nsGenericHTMLElement> mRoot;
     234                 :   nsRefPtr<nsGenericHTMLElement> mBody;
     235                 :   nsRefPtr<nsGenericHTMLElement> mHead;
     236                 : 
     237                 :   nsAutoTArray<SinkContext*, 8> mContextStack;
     238                 :   SinkContext* mCurrentContext;
     239                 :   SinkContext* mHeadContext;
     240                 : 
     241                 :   // Boolean indicating whether we've seen a <head> tag that might have had
     242                 :   // attributes once already.
     243                 :   bool mHaveSeenHead;
     244                 : 
     245                 :   // Boolean indicating whether we've notified insertion of our root content
     246                 :   // yet.  We want to make sure to only do this once.
     247                 :   bool mNotifiedRootInsertion;
     248                 : 
     249                 :   PRUint8 mScriptEnabled : 1;
     250                 :   PRUint8 mFramesEnabled : 1;
     251                 :   PRUint8 unused : 6;  // bits available if someone needs one
     252                 : 
     253                 :   nsINodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1];
     254                 : 
     255                 :   nsresult FlushTags();
     256                 : 
     257                 :   // Routines for tags that require special handling
     258                 :   nsresult CloseHTML();
     259                 :   nsresult OpenBody(const nsIParserNode& aNode);
     260                 :   nsresult CloseBody();
     261                 : 
     262                 :   nsresult OpenHeadContext();
     263                 :   void CloseHeadContext();
     264                 : 
     265                 :   // nsContentSink overrides
     266                 :   void UpdateChildCounts();
     267                 : 
     268                 :   void NotifyInsert(nsIContent* aContent,
     269                 :                     nsIContent* aChildContent,
     270                 :                     PRInt32 aIndexInContainer);
     271                 :   void NotifyRootInsertion();
     272                 :   
     273                 :   bool IsMonolithicContainer(nsHTMLTag aTag);
     274                 : 
     275                 : #ifdef NS_DEBUG
     276                 :   void ForceReflow();
     277                 : #endif
     278                 : };
     279                 : 
     280                 : class SinkContext
     281                 : {
     282                 : public:
     283                 :   SinkContext(HTMLContentSink* aSink);
     284                 :   ~SinkContext();
     285                 : 
     286                 :   nsresult Begin(nsHTMLTag aNodeType, nsGenericHTMLElement* aRoot,
     287                 :                  PRUint32 aNumFlushed, PRInt32 aInsertionPoint);
     288                 :   nsresult OpenContainer(const nsIParserNode& aNode);
     289                 :   nsresult CloseContainer(const nsHTMLTag aTag);
     290                 :   nsresult AddLeaf(const nsIParserNode& aNode);
     291                 :   nsresult AddLeaf(nsIContent* aContent);
     292                 :   nsresult End();
     293                 : 
     294                 :   nsresult GrowStack();
     295                 :   nsresult AddText(const nsAString& aText);
     296                 :   nsresult FlushText(bool* aDidFlush = nsnull,
     297                 :                      bool aReleaseLast = false);
     298               0 :   nsresult FlushTextAndRelease(bool* aDidFlush = nsnull)
     299                 :   {
     300               0 :     return FlushText(aDidFlush, true);
     301                 :   }
     302                 : 
     303                 :   nsresult FlushTags();
     304                 : 
     305                 :   bool     IsCurrentContainer(nsHTMLTag mType);
     306                 : 
     307                 :   void DidAddContent(nsIContent* aContent);
     308                 :   void UpdateChildCounts();
     309                 : 
     310                 : private:
     311                 :   // Function to check whether we've notified for the current content.
     312                 :   // What this actually does is check whether we've notified for all
     313                 :   // of the parent's kids.
     314                 :   bool HaveNotifiedForCurrentContent() const;
     315                 :   
     316                 : public:
     317                 :   HTMLContentSink* mSink;
     318                 :   PRInt32 mNotifyLevel;
     319                 :   nsCOMPtr<nsIContent> mLastTextNode;
     320                 :   PRInt32 mLastTextNodeSize;
     321                 : 
     322                 :   struct Node {
     323                 :     nsHTMLTag mType;
     324                 :     nsGenericHTMLElement* mContent;
     325                 :     PRUint32 mNumFlushed;
     326                 :     PRInt32 mInsertionPoint;
     327                 : 
     328                 :     nsIContent *Add(nsIContent *child);
     329                 :   };
     330                 : 
     331                 :   Node* mStack;
     332                 :   PRInt32 mStackSize;
     333                 :   PRInt32 mStackPos;
     334                 : 
     335                 :   PRUnichar* mText;
     336                 :   PRInt32 mTextLength;
     337                 :   PRInt32 mTextSize;
     338                 : 
     339                 : private:
     340                 :   bool mLastTextCharWasCR;
     341                 : };
     342                 : 
     343                 : //----------------------------------------------------------------------
     344                 : 
     345                 : #ifdef NS_DEBUG
     346                 : void
     347               0 : HTMLContentSink::SinkTraceNode(PRUint32 aBit,
     348                 :                                const char* aMsg,
     349                 :                                const nsHTMLTag aTag,
     350                 :                                PRInt32 aStackPos,
     351                 :                                void* aThis)
     352                 : {
     353               0 :   if (SINK_LOG_TEST(gSinkLogModuleInfo, aBit)) {
     354               0 :     nsIParserService *parserService = nsContentUtils::GetParserService();
     355               0 :     if (!parserService)
     356               0 :       return;
     357                 : 
     358               0 :     NS_ConvertUTF16toUTF8 tag(parserService->HTMLIdToStringTag(aTag));
     359                 :     PR_LogPrint("%s: this=%p node='%s' stackPos=%d", 
     360               0 :                 aMsg, aThis, tag.get(), aStackPos);
     361                 :   }
     362                 : }
     363                 : #endif
     364                 : 
     365                 : nsresult
     366               0 : HTMLContentSink::AddAttributes(const nsIParserNode& aNode,
     367                 :                                nsIContent* aContent, bool aNotify,
     368                 :                                bool aCheckIfPresent)
     369                 : {
     370                 :   // Add tag attributes to the content attributes
     371                 : 
     372               0 :   PRInt32 ac = aNode.GetAttributeCount();
     373                 : 
     374               0 :   if (ac == 0) {
     375                 :     // No attributes, nothing to do. Do an early return to avoid
     376                 :     // constructing the nsAutoString object for nothing.
     377                 : 
     378               0 :     return NS_OK;
     379                 :   }
     380                 : 
     381               0 :   nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
     382                 : 
     383                 :   // The attributes are on the parser node in the order they came in in the
     384                 :   // source.  What we want to happen if a single attribute is set multiple
     385                 :   // times on an element is that the first time should "win".  That is, <input
     386                 :   // value="foo" value="bar"> should show "foo".  So we loop over the
     387                 :   // attributes backwards; this ensures that the first attribute in the set
     388                 :   // wins.  This does mean that we do some extra work in the case when the same
     389                 :   // attribute is set multiple times, but we save a HasAttr call in the much
     390                 :   // more common case of reasonable HTML.  Note that if aCheckIfPresent is set
     391                 :   // then we actually want to loop _forwards_ to preserve the "first attribute
     392                 :   // wins" behavior.  That does mean that when aCheckIfPresent is set the order
     393                 :   // of attributes will get "reversed" from the point of view of the
     394                 :   // serializer.  But aCheckIfPresent is only true for malformed documents with
     395                 :   // multiple <html>, <head>, or <body> tags, so we're doing fixup anyway at
     396                 :   // that point.
     397                 : 
     398                 :   PRInt32 i, limit, step;
     399               0 :   if (aCheckIfPresent) {
     400               0 :     i = 0;
     401               0 :     limit = ac;
     402               0 :     step = 1;
     403                 :   } else {
     404               0 :     i = ac - 1;
     405               0 :     limit = -1;
     406               0 :     step = -1;
     407                 :   }
     408                 :   
     409               0 :   nsAutoString key;
     410               0 :   for (; i != limit; i += step) {
     411                 :     // Get lower-cased key
     412               0 :     nsresult rv = nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key);
     413               0 :     if (NS_FAILED(rv)) {
     414               0 :       return rv;
     415                 :     }
     416                 : 
     417               0 :     nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);
     418                 : 
     419               0 :     if (aCheckIfPresent && aContent->HasAttr(kNameSpaceID_None, keyAtom)) {
     420               0 :       continue;
     421                 :     }
     422                 : 
     423                 :     // Get value and remove mandatory quotes
     424                 :     static const char* kWhitespace = "\n\r\t\b";
     425                 : 
     426                 :     // Bug 114997: Don't trim whitespace on <input value="...">:
     427                 :     // Using ?: outside the function call would be more efficient, but
     428                 :     // we don't trust ?: with references.
     429                 :     const nsAString& v =
     430                 :       nsContentUtils::TrimCharsInSet(
     431                 :         (nodeType == eHTMLTag_input &&
     432               0 :           keyAtom == nsGkAtoms::value) ?
     433               0 :         "" : kWhitespace, aNode.GetValueAt(i));
     434                 : 
     435               0 :     if (nodeType == eHTMLTag_a && keyAtom == nsGkAtoms::name) {
     436               0 :       NS_ConvertUTF16toUTF8 cname(v);
     437               0 :       NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
     438                 : 
     439                 :       // Add attribute to content
     440               0 :       aContent->SetAttr(kNameSpaceID_None, keyAtom, uv, aNotify);
     441                 :     } else {
     442                 :       // Add attribute to content
     443               0 :       aContent->SetAttr(kNameSpaceID_None, keyAtom, v, aNotify);
     444                 :     }
     445                 :   }
     446                 : 
     447               0 :   return NS_OK;
     448                 : }
     449                 : 
     450                 : /**
     451                 :  * Factory subroutine to create all of the html content objects.
     452                 :  */
     453                 : already_AddRefed<nsGenericHTMLElement>
     454               0 : HTMLContentSink::CreateContentObject(const nsIParserNode& aNode,
     455                 :                                      nsHTMLTag aNodeType)
     456                 : {
     457                 :   // Find/create atom for the tag name
     458                 : 
     459               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
     460                 : 
     461               0 :   if (aNodeType == eHTMLTag_userdefined) {
     462               0 :     nsAutoString lower;
     463               0 :     nsContentUtils::ASCIIToLower(aNode.GetText(), lower);
     464               0 :     nsCOMPtr<nsIAtom> name = do_GetAtom(lower);
     465                 :     nodeInfo = mNodeInfoManager->GetNodeInfo(name, nsnull, kNameSpaceID_XHTML,
     466               0 :                                              nsIDOMNode::ELEMENT_NODE);
     467                 :   }
     468               0 :   else if (mNodeInfoCache[aNodeType]) {
     469               0 :     nodeInfo = mNodeInfoCache[aNodeType];
     470                 :   }
     471                 :   else {
     472               0 :     nsIParserService *parserService = nsContentUtils::GetParserService();
     473               0 :     if (!parserService)
     474               0 :       return nsnull;
     475                 : 
     476               0 :     nsIAtom *name = parserService->HTMLIdToAtomTag(aNodeType);
     477               0 :     NS_ASSERTION(name, "What? Reverse mapping of id to string broken!!!");
     478                 : 
     479                 :     nodeInfo = mNodeInfoManager->GetNodeInfo(name, nsnull, kNameSpaceID_XHTML,
     480               0 :                                              nsIDOMNode::ELEMENT_NODE);
     481               0 :     NS_IF_ADDREF(mNodeInfoCache[aNodeType] = nodeInfo);
     482                 :   }
     483                 : 
     484               0 :   NS_ENSURE_TRUE(nodeInfo, nsnull);
     485                 : 
     486                 :   // Make the content object
     487               0 :   return CreateHTMLElement(aNodeType, nodeInfo.forget(), FROM_PARSER_NETWORK);
     488                 : }
     489                 : 
     490                 : nsresult
     491             791 : NS_NewHTMLElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo,
     492                 :                   FromParser aFromParser)
     493                 : {
     494             791 :   *aResult = nsnull;
     495                 : 
     496            1582 :   nsCOMPtr<nsINodeInfo> nodeInfo = aNodeInfo;
     497                 : 
     498             791 :   nsIParserService* parserService = nsContentUtils::GetParserService();
     499             791 :   if (!parserService)
     500               0 :     return NS_ERROR_OUT_OF_MEMORY;
     501                 : 
     502             791 :   nsIAtom *name = nodeInfo->NameAtom();
     503                 : 
     504             791 :   NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML), 
     505                 :                "Trying to HTML elements that don't have the XHTML namespace");
     506                 :   
     507                 :   *aResult = CreateHTMLElement(parserService->
     508             791 :                                  HTMLCaseSensitiveAtomTagToId(name),
     509            1582 :                                nodeInfo.forget(), aFromParser).get();
     510             791 :   return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     511                 : }
     512                 : 
     513                 : already_AddRefed<nsGenericHTMLElement>
     514             791 : CreateHTMLElement(PRUint32 aNodeType, already_AddRefed<nsINodeInfo> aNodeInfo,
     515                 :                   FromParser aFromParser)
     516                 : {
     517             791 :   NS_ASSERTION(aNodeType <= NS_HTML_TAG_MAX ||
     518                 :                aNodeType == eHTMLTag_userdefined,
     519                 :                "aNodeType is out of bounds");
     520                 : 
     521             791 :   contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType];
     522                 : 
     523             791 :   NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
     524                 :                "Don't know how to construct tag element!");
     525                 : 
     526             791 :   nsGenericHTMLElement* result = cb(aNodeInfo, aFromParser);
     527             791 :   NS_IF_ADDREF(result);
     528                 : 
     529             791 :   return result;
     530                 : }
     531                 : 
     532                 : //----------------------------------------------------------------------
     533                 : 
     534               0 : SinkContext::SinkContext(HTMLContentSink* aSink)
     535                 :   : mSink(aSink),
     536                 :     mNotifyLevel(0),
     537                 :     mLastTextNodeSize(0),
     538                 :     mStack(nsnull),
     539                 :     mStackSize(0),
     540                 :     mStackPos(0),
     541                 :     mText(nsnull),
     542                 :     mTextLength(0),
     543                 :     mTextSize(0),
     544               0 :     mLastTextCharWasCR(false)
     545                 : {
     546               0 :   MOZ_COUNT_CTOR(SinkContext);
     547               0 : }
     548                 : 
     549               0 : SinkContext::~SinkContext()
     550                 : {
     551               0 :   MOZ_COUNT_DTOR(SinkContext);
     552                 : 
     553               0 :   if (mStack) {
     554               0 :     for (PRInt32 i = 0; i < mStackPos; i++) {
     555               0 :       NS_RELEASE(mStack[i].mContent);
     556                 :     }
     557               0 :     delete [] mStack;
     558                 :   }
     559                 : 
     560               0 :   delete [] mText;
     561               0 : }
     562                 : 
     563                 : nsresult
     564               0 : SinkContext::Begin(nsHTMLTag aNodeType,
     565                 :                    nsGenericHTMLElement* aRoot,
     566                 :                    PRUint32 aNumFlushed,
     567                 :                    PRInt32 aInsertionPoint)
     568                 : {
     569               0 :   if (mStackSize < 1) {
     570               0 :     nsresult rv = GrowStack();
     571               0 :     if (NS_FAILED(rv)) {
     572               0 :       return rv;
     573                 :     }
     574                 :   }
     575                 : 
     576               0 :   mStack[0].mType = aNodeType;
     577               0 :   mStack[0].mContent = aRoot;
     578               0 :   mStack[0].mNumFlushed = aNumFlushed;
     579               0 :   mStack[0].mInsertionPoint = aInsertionPoint;
     580               0 :   NS_ADDREF(aRoot);
     581               0 :   mStackPos = 1;
     582               0 :   mTextLength = 0;
     583                 : 
     584               0 :   return NS_OK;
     585                 : }
     586                 : 
     587                 : bool
     588               0 : SinkContext::IsCurrentContainer(nsHTMLTag aTag)
     589                 : {
     590               0 :   if (aTag == mStack[mStackPos - 1].mType) {
     591               0 :     return true;
     592                 :   }
     593                 : 
     594               0 :   return false;
     595                 : }
     596                 : 
     597                 : void
     598               0 : SinkContext::DidAddContent(nsIContent* aContent)
     599                 : {
     600               0 :   if ((mStackPos == 2) && (mSink->mBody == mStack[1].mContent)) {
     601                 :     // We just finished adding something to the body
     602               0 :     mNotifyLevel = 0;
     603                 :   }
     604                 : 
     605                 :   // If we just added content to a node for which
     606                 :   // an insertion happen, we need to do an immediate
     607                 :   // notification for that insertion.
     608               0 :   if (0 < mStackPos &&
     609               0 :       mStack[mStackPos - 1].mInsertionPoint != -1 &&
     610               0 :       mStack[mStackPos - 1].mNumFlushed <
     611               0 :       mStack[mStackPos - 1].mContent->GetChildCount()) {
     612               0 :     nsIContent* parent = mStack[mStackPos - 1].mContent;
     613                 : 
     614                 : #ifdef NS_DEBUG
     615                 :     // Tracing code
     616               0 :     nsIParserService *parserService = nsContentUtils::GetParserService();
     617               0 :     if (parserService) {
     618               0 :       nsHTMLTag tag = nsHTMLTag(mStack[mStackPos - 1].mType);
     619               0 :       NS_ConvertUTF16toUTF8 str(parserService->HTMLIdToStringTag(tag));
     620                 : 
     621               0 :       SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
     622                 :                  ("SinkContext::DidAddContent: Insertion notification for "
     623                 :                   "parent=%s at position=%d and stackPos=%d",
     624                 :                   str.get(), mStack[mStackPos - 1].mInsertionPoint - 1,
     625                 :                   mStackPos - 1));
     626                 :     }
     627                 : #endif
     628                 : 
     629               0 :     PRInt32 childIndex = mStack[mStackPos - 1].mInsertionPoint - 1;
     630               0 :     NS_ASSERTION(parent->GetChildAt(childIndex) == aContent,
     631                 :                  "Flushing the wrong child.");
     632               0 :     mSink->NotifyInsert(parent, aContent, childIndex);
     633               0 :     mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount();
     634               0 :   } else if (mSink->IsTimeToNotify()) {
     635               0 :     SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
     636                 :                ("SinkContext::DidAddContent: Notification as a result of the "
     637                 :                 "interval expiring; backoff count: %d", mSink->mBackoffCount));
     638               0 :     FlushTags();
     639                 :   }
     640               0 : }
     641                 : 
     642                 : nsresult
     643               0 : SinkContext::OpenContainer(const nsIParserNode& aNode)
     644                 : {
     645               0 :   FlushTextAndRelease();
     646                 : 
     647               0 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
     648                 :                   "SinkContext::OpenContainer", 
     649                 :                   nsHTMLTag(aNode.GetNodeType()), 
     650                 :                   mStackPos, 
     651               0 :                   mSink);
     652                 : 
     653               0 :   if (mStackPos <= 0) {
     654               0 :     NS_ERROR("container w/o parent");
     655                 : 
     656               0 :     return NS_ERROR_FAILURE;
     657                 :   }
     658                 : 
     659                 :   nsresult rv;
     660               0 :   if (mStackPos + 1 > mStackSize) {
     661               0 :     rv = GrowStack();
     662               0 :     if (NS_FAILED(rv)) {
     663               0 :       return rv;
     664                 :     }
     665                 :   }
     666                 : 
     667                 :   // Create new container content object
     668               0 :   nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
     669                 :   nsGenericHTMLElement* content =
     670               0 :     mSink->CreateContentObject(aNode, nodeType).get();
     671               0 :   if (!content) {
     672               0 :     return NS_ERROR_OUT_OF_MEMORY;
     673                 :   }
     674                 : 
     675               0 :   mStack[mStackPos].mType = nodeType;
     676               0 :   mStack[mStackPos].mContent = content;
     677               0 :   mStack[mStackPos].mNumFlushed = 0;
     678               0 :   mStack[mStackPos].mInsertionPoint = -1;
     679               0 :   ++mStackPos;
     680                 : 
     681               0 :   rv = mSink->AddAttributes(aNode, content);
     682                 : 
     683               0 :   mStack[mStackPos - 2].Add(content);
     684                 : 
     685               0 :   NS_ENSURE_SUCCESS(rv, rv);
     686                 : 
     687               0 :   if (mSink->IsMonolithicContainer(nodeType)) {
     688               0 :     mSink->mInMonolithicContainer++;
     689                 :   }
     690                 : 
     691                 :   // Special handling for certain tags
     692               0 :   switch (nodeType) {
     693                 :     case eHTMLTag_form:
     694               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
     695                 :       break;
     696                 : 
     697                 :     case eHTMLTag_frameset:
     698               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
     699                 :       break;
     700                 : 
     701                 :     case eHTMLTag_noembed:
     702                 :     case eHTMLTag_noframes:
     703               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for noembed/noframes.");
     704                 :       break;
     705                 : 
     706                 :     case eHTMLTag_script:
     707                 :     case eHTMLTag_style:
     708               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for styles and scripts.");
     709                 :       break;
     710                 : 
     711                 :     case eHTMLTag_button:
     712                 : #ifdef MOZ_MEDIA
     713                 :     case eHTMLTag_audio:
     714                 :     case eHTMLTag_video:
     715                 : #endif
     716               0 :       content->DoneCreatingElement();
     717               0 :       break;
     718                 : 
     719                 :     default:
     720               0 :       break;
     721                 :   }
     722                 : 
     723               0 :   return NS_OK;
     724                 : }
     725                 : 
     726                 : bool
     727               0 : SinkContext::HaveNotifiedForCurrentContent() const
     728                 : {
     729               0 :   if (0 < mStackPos) {
     730               0 :     nsIContent* parent = mStack[mStackPos - 1].mContent;
     731               0 :     return mStack[mStackPos-1].mNumFlushed == parent->GetChildCount();
     732                 :   }
     733                 : 
     734               0 :   return true;
     735                 : }
     736                 : 
     737                 : nsIContent *
     738               0 : SinkContext::Node::Add(nsIContent *child)
     739                 : {
     740               0 :   NS_ASSERTION(mContent, "No parent to insert/append into!");
     741               0 :   if (mInsertionPoint != -1) {
     742               0 :     NS_ASSERTION(mNumFlushed == mContent->GetChildCount(),
     743                 :                  "Inserting multiple children without flushing.");
     744               0 :     mContent->InsertChildAt(child, mInsertionPoint++, false);
     745                 :   } else {
     746               0 :     mContent->AppendChildTo(child, false);
     747                 :   }
     748               0 :   return child;
     749                 : }
     750                 : 
     751                 : nsresult
     752               0 : SinkContext::CloseContainer(const nsHTMLTag aTag)
     753                 : {
     754               0 :   nsresult result = NS_OK;
     755                 : 
     756                 :   // Flush any collected text content. Release the last text
     757                 :   // node to indicate that no more should be added to it.
     758               0 :   FlushTextAndRelease();
     759                 : 
     760               0 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
     761                 :                   "SinkContext::CloseContainer", 
     762               0 :                   aTag, mStackPos - 1, mSink);
     763                 : 
     764               0 :   NS_ASSERTION(mStackPos > 0,
     765                 :                "stack out of bounds. wrong context probably!");
     766                 : 
     767               0 :   if (mStackPos <= 0) {
     768               0 :     return NS_OK; // Fix crash - Ref. bug 45975 or 45007
     769                 :   }
     770                 : 
     771               0 :   --mStackPos;
     772               0 :   nsHTMLTag nodeType = mStack[mStackPos].mType;
     773                 : 
     774               0 :   NS_ASSERTION(nodeType == aTag,
     775                 :                "Tag mismatch.  Closing tag on wrong context or something?");
     776                 : 
     777               0 :   nsGenericHTMLElement* content = mStack[mStackPos].mContent;
     778                 : 
     779               0 :   content->Compact();
     780                 : 
     781                 :   // If we're in a state where we do append notifications as
     782                 :   // we go up the tree, and we're at the level where the next
     783                 :   // notification needs to be done, do the notification.
     784               0 :   if (mNotifyLevel >= mStackPos) {
     785                 :     // Check to see if new content has been added after our last
     786                 :     // notification
     787                 : 
     788               0 :     if (mStack[mStackPos].mNumFlushed < content->GetChildCount()) {
     789                 : #ifdef NS_DEBUG
     790                 :       {
     791                 :         // Tracing code
     792               0 :         SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
     793                 :                    ("SinkContext::CloseContainer: reflow on notifyImmediate "
     794                 :                     "tag=%s newIndex=%d stackPos=%d",
     795                 :                     nsAtomCString(mStack[mStackPos].mContent->Tag()).get(),
     796                 :                     mStack[mStackPos].mNumFlushed, mStackPos));
     797                 :       }
     798                 : #endif
     799               0 :       mSink->NotifyAppend(content, mStack[mStackPos].mNumFlushed);
     800               0 :       mStack[mStackPos].mNumFlushed = content->GetChildCount();
     801                 :     }
     802                 : 
     803                 :     // Indicate that notification has now happened at this level
     804               0 :     mNotifyLevel = mStackPos - 1;
     805                 :   }
     806                 : 
     807               0 :   if (mSink->IsMonolithicContainer(nodeType)) {
     808               0 :     --mSink->mInMonolithicContainer;
     809                 :   }
     810                 : 
     811               0 :   DidAddContent(content);
     812                 : 
     813                 :   // Special handling for certain tags
     814               0 :   switch (nodeType) {
     815                 :   case eHTMLTag_noembed:
     816                 :   case eHTMLTag_noframes:
     817               0 :     MOZ_NOT_REACHED("Must not use HTMLContentSink for noembed/noframes.");
     818                 :     break;
     819                 : 
     820                 :   case eHTMLTag_form:
     821               0 :     MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
     822                 :     break;
     823                 : 
     824                 : #ifdef MOZ_MEDIA
     825                 :   case eHTMLTag_video:
     826                 :   case eHTMLTag_audio:
     827                 : #endif
     828                 :   case eHTMLTag_select:
     829                 :   case eHTMLTag_textarea:
     830                 :   case eHTMLTag_object:
     831                 :   case eHTMLTag_applet:
     832                 :   case eHTMLTag_title:
     833               0 :     content->DoneAddingChildren(HaveNotifiedForCurrentContent());
     834               0 :     break;
     835                 : 
     836                 :   case eHTMLTag_script:
     837               0 :     MOZ_NOT_REACHED("Must not use HTMLContentSink to run scripts.");
     838                 :     result = NS_ERROR_NOT_IMPLEMENTED;
     839                 :     break;
     840                 : 
     841                 :   case eHTMLTag_style:
     842               0 :     MOZ_NOT_REACHED("Must not use HTMLContentSink for styles.");
     843                 :     result = NS_ERROR_NOT_IMPLEMENTED;
     844                 :     break;
     845                 : 
     846                 :   default:
     847               0 :     break;
     848                 :   }
     849                 : 
     850               0 :   NS_IF_RELEASE(content);
     851                 : 
     852                 : #ifdef DEBUG
     853               0 :   if (SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
     854               0 :     mSink->ForceReflow();
     855                 :   }
     856                 : #endif
     857                 : 
     858               0 :   return result;
     859                 : }
     860                 : 
     861                 : nsresult
     862               0 : SinkContext::AddLeaf(const nsIParserNode& aNode)
     863                 : {
     864               0 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
     865                 :                   "SinkContext::AddLeaf", 
     866                 :                   nsHTMLTag(aNode.GetNodeType()), 
     867               0 :                   mStackPos, mSink);
     868                 : 
     869               0 :   nsresult rv = NS_OK;
     870                 : 
     871               0 :   switch (aNode.GetTokenType()) {
     872                 :   case eToken_start:
     873                 :     {
     874               0 :       FlushTextAndRelease();
     875                 : 
     876                 :       // Create new leaf content object
     877               0 :       nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
     878                 :       nsRefPtr<nsGenericHTMLElement> content =
     879               0 :         mSink->CreateContentObject(aNode, nodeType);
     880               0 :       NS_ENSURE_TRUE(content, NS_ERROR_OUT_OF_MEMORY);
     881                 : 
     882               0 :       rv = mSink->AddAttributes(aNode, content);
     883               0 :       NS_ENSURE_SUCCESS(rv, rv);
     884                 : 
     885                 :       // Add new leaf to its parent
     886               0 :       AddLeaf(content);
     887                 : 
     888                 :       // Additional processing needed once the element is in the tree
     889               0 :       switch (nodeType) {
     890                 :       case eHTMLTag_meta:
     891               0 :         MOZ_NOT_REACHED("Must not use HTMLContentSink for metas.");
     892                 :         rv = NS_ERROR_NOT_IMPLEMENTED;
     893                 :         break;
     894                 : 
     895                 :       case eHTMLTag_input:
     896               0 :         content->DoneCreatingElement();
     897               0 :         break;
     898                 : 
     899                 :       case eHTMLTag_menuitem:
     900               0 :         content->DoneCreatingElement();
     901               0 :         break;
     902                 : 
     903                 :       default:
     904               0 :         break;
     905                 :       }
     906                 :     }
     907               0 :     break;
     908                 : 
     909                 :   case eToken_text:
     910                 :   case eToken_whitespace:
     911                 :   case eToken_newline:
     912               0 :     rv = AddText(aNode.GetText());
     913                 : 
     914               0 :     break;
     915                 :   case eToken_entity:
     916                 :     {
     917               0 :       nsAutoString tmp;
     918               0 :       PRInt32 unicode = aNode.TranslateToUnicodeStr(tmp);
     919               0 :       if (unicode < 0) {
     920               0 :         rv = AddText(aNode.GetText());
     921                 :       } else {
     922                 :         // Map carriage returns to newlines
     923               0 :         if (!tmp.IsEmpty()) {
     924               0 :           if (tmp.CharAt(0) == '\r') {
     925               0 :             tmp.Assign((PRUnichar)'\n');
     926                 :           }
     927               0 :           rv = AddText(tmp);
     928                 :         }
     929                 :       }
     930                 :     }
     931                 : 
     932               0 :     break;
     933                 :   default:
     934               0 :     break;
     935                 :   }
     936                 : 
     937               0 :   return rv;
     938                 : }
     939                 : 
     940                 : nsresult
     941               0 : SinkContext::AddLeaf(nsIContent* aContent)
     942                 : {
     943               0 :   NS_ASSERTION(mStackPos > 0, "leaf w/o container");
     944               0 :   if (mStackPos <= 0) {
     945               0 :     return NS_ERROR_FAILURE;
     946                 :   }
     947                 :   
     948               0 :   DidAddContent(mStack[mStackPos - 1].Add(aContent));
     949                 : 
     950                 : #ifdef DEBUG
     951               0 :   if (SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
     952               0 :     mSink->ForceReflow();
     953                 :   }
     954                 : #endif
     955                 : 
     956               0 :   return NS_OK;
     957                 : }
     958                 : 
     959                 : nsresult
     960               0 : SinkContext::End()
     961                 : {
     962               0 :   for (PRInt32 i = 0; i < mStackPos; i++) {
     963               0 :     NS_RELEASE(mStack[i].mContent);
     964                 :   }
     965                 : 
     966               0 :   mStackPos = 0;
     967               0 :   mTextLength = 0;
     968                 : 
     969               0 :   return NS_OK;
     970                 : }
     971                 : 
     972                 : nsresult
     973               0 : SinkContext::GrowStack()
     974                 : {
     975               0 :   PRInt32 newSize = mStackSize * 2;
     976               0 :   if (newSize == 0) {
     977               0 :     newSize = 32;
     978                 :   }
     979                 : 
     980               0 :   Node* stack = new Node[newSize];
     981               0 :   if (!stack) {
     982               0 :     return NS_ERROR_OUT_OF_MEMORY;
     983                 :   }
     984                 : 
     985               0 :   if (mStackPos != 0) {
     986               0 :     memcpy(stack, mStack, sizeof(Node) * mStackPos);
     987               0 :     delete [] mStack;
     988                 :   }
     989                 : 
     990               0 :   mStack = stack;
     991               0 :   mStackSize = newSize;
     992                 : 
     993               0 :   return NS_OK;
     994                 : }
     995                 : 
     996                 : /**
     997                 :  * Add textual content to the current running text buffer. If the text buffer
     998                 :  * overflows, flush out the text by creating a text content object and adding
     999                 :  * it to the content tree.
    1000                 :  */
    1001                 : 
    1002                 : // XXX If we get a giant string grow the buffer instead of chopping it
    1003                 : // up???
    1004                 : nsresult
    1005               0 : SinkContext::AddText(const nsAString& aText)
    1006                 : {
    1007               0 :   PRInt32 addLen = aText.Length();
    1008               0 :   if (addLen == 0) {
    1009               0 :     return NS_OK;
    1010                 :   }
    1011                 :   
    1012                 :   // Create buffer when we first need it
    1013               0 :   if (mTextSize == 0) {
    1014               0 :     mText = new PRUnichar[4096];
    1015               0 :     if (!mText) {
    1016               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1017                 :     }
    1018               0 :     mTextSize = 4096;
    1019                 :   }
    1020                 : 
    1021                 :   // Copy data from string into our buffer; flush buffer when it fills up
    1022               0 :   PRInt32 offset = 0;
    1023                 : 
    1024               0 :   while (addLen != 0) {
    1025               0 :     PRInt32 amount = mTextSize - mTextLength;
    1026                 : 
    1027               0 :     if (amount > addLen) {
    1028               0 :       amount = addLen;
    1029                 :     }
    1030                 : 
    1031               0 :     if (amount == 0) {
    1032                 :       // Don't release last text node so we can add to it again
    1033               0 :       nsresult rv = FlushText();
    1034               0 :       if (NS_FAILED(rv)) {
    1035               0 :         return rv;
    1036                 :       }
    1037                 : 
    1038                 :       // Go back to the top of the loop so we re-calculate amount and
    1039                 :       // don't fall through to CopyNewlineNormalizedUnicodeTo with a
    1040                 :       // zero-length amount (which invalidates mLastTextCharWasCR).
    1041               0 :       continue;
    1042                 :     }
    1043                 : 
    1044                 :     mTextLength +=
    1045                 :       nsContentUtils::CopyNewlineNormalizedUnicodeTo(aText, offset,
    1046                 :                                                      &mText[mTextLength],
    1047                 :                                                      amount,
    1048               0 :                                                      mLastTextCharWasCR);
    1049               0 :     offset += amount;
    1050               0 :     addLen -= amount;
    1051                 :   }
    1052                 : 
    1053               0 :   return NS_OK;
    1054                 : }
    1055                 : 
    1056                 : /**
    1057                 :  * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
    1058                 :  *
    1059                 :  * Flush all elements that have been seen so far such that
    1060                 :  * they are visible in the tree. Specifically, make sure
    1061                 :  * that they are all added to their respective parents.
    1062                 :  * Also, do notification at the top for all content that
    1063                 :  * has been newly added so that the frame tree is complete.
    1064                 :  */
    1065                 : nsresult
    1066               0 : SinkContext::FlushTags()
    1067                 : {
    1068               0 :   mSink->mDeferredFlushTags = false;
    1069               0 :   bool oldBeganUpdate = mSink->mBeganUpdate;
    1070               0 :   PRUint32 oldUpdates = mSink->mUpdatesInNotification;
    1071                 : 
    1072               0 :   ++(mSink->mInNotification);
    1073               0 :   mSink->mUpdatesInNotification = 0;
    1074                 :   {
    1075                 :     // Scope so we call EndUpdate before we decrease mInNotification
    1076                 :     mozAutoDocUpdate updateBatch(mSink->mDocument, UPDATE_CONTENT_MODEL,
    1077               0 :                                  true);
    1078               0 :     mSink->mBeganUpdate = true;
    1079                 : 
    1080                 :     // Don't release last text node in case we need to add to it again
    1081               0 :     FlushText();
    1082                 : 
    1083                 :     // Start from the base of the stack (growing downward) and do
    1084                 :     // a notification from the node that is closest to the root of
    1085                 :     // tree for any content that has been added.
    1086                 : 
    1087                 :     // Note that we can start at stackPos == 0 here, because it's the caller's
    1088                 :     // responsibility to handle flushing interactions between contexts (see
    1089                 :     // HTMLContentSink::BeginContext).
    1090               0 :     PRInt32 stackPos = 0;
    1091               0 :     bool flushed = false;
    1092                 :     PRUint32 childCount;
    1093                 :     nsGenericHTMLElement* content;
    1094                 : 
    1095               0 :     while (stackPos < mStackPos) {
    1096               0 :       content = mStack[stackPos].mContent;
    1097               0 :       childCount = content->GetChildCount();
    1098                 : 
    1099               0 :       if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
    1100                 : #ifdef NS_DEBUG
    1101                 :         {
    1102                 :           // Tracing code
    1103               0 :           SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1104                 :                      ("SinkContext::FlushTags: tag=%s from newindex=%d at "
    1105                 :                       "stackPos=%d",
    1106                 :                       nsAtomCString(mStack[stackPos].mContent->Tag()).get(),
    1107                 :                       mStack[stackPos].mNumFlushed, stackPos));
    1108                 :         }
    1109                 : #endif
    1110               0 :         if (mStack[stackPos].mInsertionPoint != -1) {
    1111                 :           // We might have popped the child off our stack already
    1112                 :           // but not notified on it yet, which is why we have to get it
    1113                 :           // directly from its parent node.
    1114                 : 
    1115               0 :           PRInt32 childIndex = mStack[stackPos].mInsertionPoint - 1;
    1116               0 :           nsIContent* child = content->GetChildAt(childIndex);
    1117                 :           // Child not on stack anymore; can't assert it's correct
    1118               0 :           NS_ASSERTION(!(mStackPos > (stackPos + 1)) ||
    1119                 :                        (child == mStack[stackPos + 1].mContent),
    1120                 :                        "Flushing the wrong child.");
    1121               0 :           mSink->NotifyInsert(content, child, childIndex);
    1122                 :         } else {
    1123               0 :           mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
    1124                 :         }
    1125                 : 
    1126               0 :         flushed = true;
    1127                 :       }
    1128                 : 
    1129               0 :       mStack[stackPos].mNumFlushed = childCount;
    1130               0 :       stackPos++;
    1131                 :     }
    1132               0 :     mNotifyLevel = mStackPos - 1;
    1133                 :   }
    1134               0 :   --(mSink->mInNotification);
    1135                 : 
    1136               0 :   if (mSink->mUpdatesInNotification > 1) {
    1137               0 :     UpdateChildCounts();
    1138                 :   }
    1139                 : 
    1140               0 :   mSink->mUpdatesInNotification = oldUpdates;
    1141               0 :   mSink->mBeganUpdate = oldBeganUpdate;
    1142                 : 
    1143               0 :   return NS_OK;
    1144                 : }
    1145                 : 
    1146                 : /**
    1147                 :  * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
    1148                 :  */
    1149                 : void
    1150               0 : SinkContext::UpdateChildCounts()
    1151                 : {
    1152                 :   // Start from the top of the stack (growing upwards) and see if any
    1153                 :   // new content has been appended. If so, we recognize that reflows
    1154                 :   // have been generated for it and we should make sure that no
    1155                 :   // further reflows occur.  Note that we have to include stackPos == 0
    1156                 :   // to properly notify on kids of <html>.
    1157               0 :   PRInt32 stackPos = mStackPos - 1;
    1158               0 :   while (stackPos >= 0) {
    1159               0 :     Node & node = mStack[stackPos];
    1160               0 :     node.mNumFlushed = node.mContent->GetChildCount();
    1161                 : 
    1162               0 :     stackPos--;
    1163                 :   }
    1164                 : 
    1165               0 :   mNotifyLevel = mStackPos - 1;
    1166               0 : }
    1167                 : 
    1168                 : /**
    1169                 :  * Flush any buffered text out by creating a text content object and
    1170                 :  * adding it to the content.
    1171                 :  */
    1172                 : nsresult
    1173               0 : SinkContext::FlushText(bool* aDidFlush, bool aReleaseLast)
    1174                 : {
    1175               0 :   nsresult rv = NS_OK;
    1176               0 :   bool didFlush = false;
    1177                 : 
    1178               0 :   if (mTextLength != 0) {
    1179               0 :     if (mLastTextNode) {
    1180               0 :       if ((mLastTextNodeSize + mTextLength) > mSink->mMaxTextRun) {
    1181               0 :         mLastTextNodeSize = 0;
    1182               0 :         mLastTextNode = nsnull;
    1183               0 :         FlushText(aDidFlush, aReleaseLast);
    1184                 :       } else {
    1185               0 :         bool notify = HaveNotifiedForCurrentContent();
    1186                 :         // We could probably always increase mInNotification here since
    1187                 :         // if AppendText doesn't notify it shouldn't trigger evil code.
    1188                 :         // But just in case it does, we don't want to mask any notifications.
    1189               0 :         if (notify) {
    1190               0 :           ++mSink->mInNotification;
    1191                 :         }
    1192               0 :         rv = mLastTextNode->AppendText(mText, mTextLength, notify);
    1193               0 :         if (notify) {
    1194               0 :           --mSink->mInNotification;
    1195                 :         }
    1196                 : 
    1197               0 :         mLastTextNodeSize += mTextLength;
    1198               0 :         mTextLength = 0;
    1199               0 :         didFlush = true;
    1200                 :       }
    1201                 :     } else {
    1202               0 :       nsCOMPtr<nsIContent> textContent;
    1203               0 :       rv = NS_NewTextNode(getter_AddRefs(textContent),
    1204               0 :                           mSink->mNodeInfoManager);
    1205               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1206                 : 
    1207               0 :       mLastTextNode = textContent;
    1208                 : 
    1209                 :       // Set the text in the text node
    1210               0 :       mLastTextNode->SetText(mText, mTextLength, false);
    1211                 : 
    1212                 :       // Eat up the rest of the text up in state.
    1213               0 :       mLastTextNodeSize += mTextLength;
    1214               0 :       mTextLength = 0;
    1215                 : 
    1216               0 :       rv = AddLeaf(mLastTextNode);
    1217               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1218                 : 
    1219               0 :       didFlush = true;
    1220                 :     }
    1221                 :   }
    1222                 : 
    1223               0 :   if (aDidFlush) {
    1224               0 :     *aDidFlush = didFlush;
    1225                 :   }
    1226                 : 
    1227               0 :   if (aReleaseLast) {
    1228               0 :     mLastTextNodeSize = 0;
    1229               0 :     mLastTextNode = nsnull;
    1230               0 :     mLastTextCharWasCR = false;
    1231                 :   }
    1232                 : 
    1233                 : #ifdef DEBUG
    1234               0 :   if (didFlush &&
    1235                 :       SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
    1236               0 :     mSink->ForceReflow();
    1237                 :   }
    1238                 : #endif
    1239                 : 
    1240               0 :   return rv;
    1241                 : }
    1242                 : 
    1243                 : 
    1244                 : nsresult
    1245               0 : NS_NewHTMLContentSink(nsIHTMLContentSink** aResult,
    1246                 :                       nsIDocument* aDoc,
    1247                 :                       nsIURI* aURI,
    1248                 :                       nsISupports* aContainer,
    1249                 :                       nsIChannel* aChannel)
    1250                 : {
    1251               0 :   NS_ENSURE_ARG_POINTER(aResult);
    1252                 : 
    1253               0 :   nsRefPtr<HTMLContentSink> it = new HTMLContentSink();
    1254                 : 
    1255               0 :   if (!it) {
    1256               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1257                 :   }
    1258                 : 
    1259               0 :   nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
    1260                 : 
    1261               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1262                 : 
    1263               0 :   *aResult = it;
    1264               0 :   NS_ADDREF(*aResult);
    1265                 : 
    1266               0 :   return NS_OK;
    1267                 : }
    1268                 : 
    1269               0 : HTMLContentSink::HTMLContentSink()
    1270                 : {
    1271                 :   // Note: operator new zeros our memory
    1272                 : 
    1273                 : 
    1274                 : #ifdef NS_DEBUG
    1275               0 :   if (!gSinkLogModuleInfo) {
    1276               0 :     gSinkLogModuleInfo = PR_NewLogModule("htmlcontentsink");
    1277                 :   }
    1278                 : #endif
    1279               0 : }
    1280                 : 
    1281               0 : HTMLContentSink::~HTMLContentSink()
    1282                 : {
    1283               0 :   if (mNotificationTimer) {
    1284               0 :     mNotificationTimer->Cancel();
    1285                 :   }
    1286                 : 
    1287               0 :   PRInt32 numContexts = mContextStack.Length();
    1288                 : 
    1289               0 :   if (mCurrentContext == mHeadContext && numContexts > 0) {
    1290                 :     // Pop off the second html context if it's not done earlier
    1291               0 :     mContextStack.RemoveElementAt(--numContexts);
    1292                 :   }
    1293                 : 
    1294                 :   PRInt32 i;
    1295               0 :   for (i = 0; i < numContexts; i++) {
    1296               0 :     SinkContext* sc = mContextStack.ElementAt(i);
    1297               0 :     if (sc) {
    1298               0 :       sc->End();
    1299               0 :       if (sc == mCurrentContext) {
    1300               0 :         mCurrentContext = nsnull;
    1301                 :       }
    1302                 : 
    1303               0 :       delete sc;
    1304                 :     }
    1305                 :   }
    1306                 : 
    1307               0 :   if (mCurrentContext == mHeadContext) {
    1308               0 :     mCurrentContext = nsnull;
    1309                 :   }
    1310                 : 
    1311               0 :   delete mCurrentContext;
    1312                 : 
    1313               0 :   delete mHeadContext;
    1314                 : 
    1315               0 :   for (i = 0; PRUint32(i) < ArrayLength(mNodeInfoCache); ++i) {
    1316               0 :     NS_IF_RELEASE(mNodeInfoCache[i]);
    1317                 :   }
    1318               0 : }
    1319                 : 
    1320            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLContentSink)
    1321                 : 
    1322               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLContentSink, nsContentSink)
    1323               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHTMLDocument)
    1324               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
    1325               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBody)
    1326               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHead)
    1327               0 :   for (PRUint32 i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) {
    1328               0 :     NS_IF_RELEASE(tmp->mNodeInfoCache[i]);
    1329                 :   }
    1330               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1331               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLContentSink,
    1332                 :                                                   nsContentSink)
    1333               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHTMLDocument)
    1334               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
    1335               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBody)
    1336               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHead)
    1337               0 :   for (PRUint32 i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) {
    1338               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfoCache[i]");
    1339               0 :     cb.NoteXPCOMChild(tmp->mNodeInfoCache[i]);
    1340                 :   }
    1341               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1342                 : 
    1343               0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLContentSink)
    1344                 :   NS_INTERFACE_TABLE_BEGIN
    1345                 :     NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIContentSink)
    1346                 :     NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIHTMLContentSink)
    1347                 : #if DEBUG
    1348                 :     NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIDebugDumpContent)
    1349                 : #endif
    1350               0 :   NS_INTERFACE_TABLE_END
    1351               0 : NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink)
    1352                 : 
    1353               0 : NS_IMPL_ADDREF_INHERITED(HTMLContentSink, nsContentSink)
    1354               0 : NS_IMPL_RELEASE_INHERITED(HTMLContentSink, nsContentSink)
    1355                 : 
    1356                 : static bool
    1357               0 : IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer)
    1358                 : {
    1359               0 :   NS_ENSURE_TRUE(aDoc && aContainer, true);
    1360                 : 
    1361               0 :   nsCOMPtr<nsIScriptGlobalObject> globalObject = aDoc->GetScriptGlobalObject();
    1362                 : 
    1363                 :   // Getting context is tricky if the document hasn't had its
    1364                 :   // GlobalObject set yet
    1365               0 :   if (!globalObject) {
    1366               0 :     nsCOMPtr<nsIScriptGlobalObjectOwner> owner = do_GetInterface(aContainer);
    1367               0 :     NS_ENSURE_TRUE(owner, true);
    1368                 : 
    1369               0 :     globalObject = owner->GetScriptGlobalObject();
    1370               0 :     NS_ENSURE_TRUE(globalObject, true);
    1371                 :   }
    1372                 : 
    1373               0 :   nsIScriptContext *scriptContext = globalObject->GetContext();
    1374               0 :   NS_ENSURE_TRUE(scriptContext, true);
    1375                 : 
    1376               0 :   JSContext* cx = scriptContext->GetNativeContext();
    1377               0 :   NS_ENSURE_TRUE(cx, true);
    1378                 : 
    1379               0 :   bool enabled = true;
    1380               0 :   nsContentUtils::GetSecurityManager()->
    1381               0 :     CanExecuteScripts(cx, aDoc->NodePrincipal(), &enabled);
    1382               0 :   return enabled;
    1383                 : }
    1384                 : 
    1385                 : nsresult
    1386               0 : HTMLContentSink::Init(nsIDocument* aDoc,
    1387                 :                       nsIURI* aURI,
    1388                 :                       nsISupports* aContainer,
    1389                 :                       nsIChannel* aChannel)
    1390                 : {
    1391               0 :   NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER);
    1392                 :   
    1393               0 :   nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
    1394               0 :   if (NS_FAILED(rv)) {
    1395               0 :     return rv;
    1396                 :   }
    1397                 : 
    1398               0 :   aDoc->AddObserver(this);
    1399               0 :   mIsDocumentObserver = true;
    1400               0 :   mHTMLDocument = do_QueryInterface(aDoc);
    1401                 : 
    1402               0 :   NS_ASSERTION(mDocShell, "oops no docshell!");
    1403                 : 
    1404                 :   // Find out if subframes are enabled
    1405               0 :   if (mDocShell) {
    1406               0 :     bool subFramesEnabled = true;
    1407               0 :     mDocShell->GetAllowSubframes(&subFramesEnabled);
    1408               0 :     if (subFramesEnabled) {
    1409               0 :       mFramesEnabled = true;
    1410                 :     }
    1411                 :   }
    1412                 : 
    1413                 :   // Find out if scripts are enabled, if not, show <noscript> content
    1414               0 :   if (IsScriptEnabled(aDoc, mDocShell)) {
    1415               0 :     mScriptEnabled = true;
    1416                 :   }
    1417                 : 
    1418                 : 
    1419                 :   // Changed from 8192 to greatly improve page loading performance on
    1420                 :   // large pages.  See bugzilla bug 77540.
    1421               0 :   mMaxTextRun = Preferences::GetInt("content.maxtextrun", 8191);
    1422                 : 
    1423               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
    1424                 :   nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::html, nsnull,
    1425                 :                                            kNameSpaceID_XHTML,
    1426               0 :                                            nsIDOMNode::ELEMENT_NODE);
    1427               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    1428                 : 
    1429                 :   // Make root part
    1430               0 :   mRoot = NS_NewHTMLHtmlElement(nodeInfo.forget());
    1431               0 :   if (!mRoot) {
    1432               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1433                 :   }
    1434                 : 
    1435               0 :   NS_ASSERTION(mDocument->GetChildCount() == 0,
    1436                 :                "Document should have no kids here!");
    1437               0 :   rv = mDocument->AppendChildTo(mRoot, false);
    1438               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1439                 : 
    1440                 :   // Make head part
    1441                 :   nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::head,
    1442                 :                                            nsnull, kNameSpaceID_XHTML,
    1443               0 :                                            nsIDOMNode::ELEMENT_NODE);
    1444               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    1445                 : 
    1446               0 :   mHead = NS_NewHTMLHeadElement(nodeInfo.forget());
    1447               0 :   if (NS_FAILED(rv)) {
    1448               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1449                 :   }
    1450                 : 
    1451               0 :   mRoot->AppendChildTo(mHead, false);
    1452                 : 
    1453               0 :   mCurrentContext = new SinkContext(this);
    1454               0 :   NS_ENSURE_TRUE(mCurrentContext, NS_ERROR_OUT_OF_MEMORY);
    1455               0 :   mCurrentContext->Begin(eHTMLTag_html, mRoot, 0, -1);
    1456               0 :   mContextStack.AppendElement(mCurrentContext);
    1457                 : 
    1458                 : #ifdef NS_DEBUG
    1459               0 :   nsCAutoString spec;
    1460               0 :   (void)aURI->GetSpec(spec);
    1461               0 :   SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_CALLS,
    1462                 :              ("HTMLContentSink::Init: this=%p url='%s'",
    1463                 :               this, spec.get()));
    1464                 : #endif
    1465               0 :   return NS_OK;
    1466                 : }
    1467                 : 
    1468                 : NS_IMETHODIMP
    1469               0 : HTMLContentSink::WillParse(void)
    1470                 : {
    1471               0 :   return WillParseImpl();
    1472                 : }
    1473                 : 
    1474                 : NS_IMETHODIMP
    1475               0 : HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
    1476                 : {
    1477               0 :   WillBuildModelImpl();
    1478                 : 
    1479               0 :   if (mHTMLDocument) {
    1480               0 :     nsCompatibility mode = eCompatibility_NavQuirks;
    1481               0 :     switch (aDTDMode) {
    1482                 :       case eDTDMode_full_standards:
    1483               0 :         mode = eCompatibility_FullStandards;
    1484               0 :         break;
    1485                 :       case eDTDMode_almost_standards:
    1486               0 :         mode = eCompatibility_AlmostStandards;
    1487               0 :         break;
    1488                 :       default:
    1489               0 :         break;
    1490                 :     }
    1491               0 :     mHTMLDocument->SetCompatibilityMode(mode);
    1492                 :   }
    1493                 : 
    1494                 :   // Notify document that the load is beginning
    1495               0 :   mDocument->BeginLoad();
    1496                 : 
    1497               0 :   return NS_OK;
    1498                 : }
    1499                 : 
    1500                 : NS_IMETHODIMP
    1501               0 : HTMLContentSink::DidBuildModel(bool aTerminated)
    1502                 : {
    1503               0 :   DidBuildModelImpl(aTerminated);
    1504                 : 
    1505                 :   // Reflow the last batch of content
    1506               0 :   if (mBody) {
    1507               0 :     SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1508                 :                ("HTMLContentSink::DidBuildModel: layout final content"));
    1509               0 :     mCurrentContext->FlushTags();
    1510               0 :   } else if (!mLayoutStarted) {
    1511                 :     // We never saw the body, and layout never got started. Force
    1512                 :     // layout *now*, to get an initial reflow.
    1513               0 :     SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1514                 :                ("HTMLContentSink::DidBuildModel: forcing reflow on empty "
    1515                 :                 "document"));
    1516                 : 
    1517                 :     // NOTE: only force the layout if we are NOT destroying the
    1518                 :     // docshell. If we are destroying it, then starting layout will
    1519                 :     // likely cause us to crash, or at best waste a lot of time as we
    1520                 :     // are just going to tear it down anyway.
    1521               0 :     bool bDestroying = true;
    1522               0 :     if (mDocShell) {
    1523               0 :       mDocShell->IsBeingDestroyed(&bDestroying);
    1524                 :     }
    1525                 : 
    1526               0 :     if (!bDestroying) {
    1527               0 :       StartLayout(false);
    1528                 :     }
    1529                 :   }
    1530                 : 
    1531               0 :   ScrollToRef();
    1532                 : 
    1533                 :   // Make sure we no longer respond to document mutations.  We've flushed all
    1534                 :   // our notifications out, so there's no need to do anything else here.
    1535                 : 
    1536                 :   // XXXbz I wonder whether we could End() our contexts here too, or something,
    1537                 :   // just to make sure we no longer notify...  Or is the mIsDocumentObserver
    1538                 :   // thing sufficient?
    1539               0 :   mDocument->RemoveObserver(this);
    1540               0 :   mIsDocumentObserver = false;
    1541                 :   
    1542               0 :   mDocument->EndLoad();
    1543                 : 
    1544               0 :   DropParserAndPerfHint();
    1545                 : 
    1546               0 :   return NS_OK;
    1547                 : }
    1548                 : 
    1549                 : NS_IMETHODIMP
    1550               0 : HTMLContentSink::SetParser(nsParserBase* aParser)
    1551                 : {
    1552               0 :   NS_PRECONDITION(aParser, "Should have a parser here!");
    1553               0 :   mParser = aParser;
    1554               0 :   return NS_OK;
    1555                 : }
    1556                 : 
    1557                 : NS_IMETHODIMP
    1558               0 : HTMLContentSink::BeginContext(PRInt32 aPosition)
    1559                 : {
    1560               0 :   NS_PRECONDITION(aPosition > -1, "out of bounds");
    1561                 : 
    1562               0 :   if (!mCurrentContext) {
    1563               0 :     NS_ERROR("Nonexistent context");
    1564                 : 
    1565               0 :     return NS_ERROR_FAILURE;
    1566                 :   }
    1567                 : 
    1568                 :   // Flush everything in the current context so that we don't have
    1569                 :   // to worry about insertions resulting in inconsistent frame creation.
    1570               0 :   mCurrentContext->FlushTags();
    1571                 : 
    1572                 :   // Sanity check.
    1573               0 :   if (mCurrentContext->mStackPos <= aPosition) {
    1574               0 :     NS_ERROR("Out of bounds position");
    1575               0 :     return NS_ERROR_FAILURE;
    1576                 :   }
    1577                 : 
    1578               0 :   PRInt32 insertionPoint = -1;
    1579               0 :   nsHTMLTag nodeType      = mCurrentContext->mStack[aPosition].mType;
    1580               0 :   nsGenericHTMLElement* content = mCurrentContext->mStack[aPosition].mContent;
    1581                 : 
    1582                 :   // If the content under which the new context is created
    1583                 :   // has a child on the stack, the insertion point is
    1584                 :   // before the last child.
    1585               0 :   if (aPosition < (mCurrentContext->mStackPos - 1)) {
    1586               0 :     insertionPoint = content->GetChildCount() - 1;
    1587                 :   }
    1588                 : 
    1589               0 :   SinkContext* sc = new SinkContext(this);
    1590                 :   sc->Begin(nodeType,
    1591                 :             content,
    1592               0 :             mCurrentContext->mStack[aPosition].mNumFlushed,
    1593               0 :             insertionPoint);
    1594               0 :   NS_ADDREF(sc->mSink);
    1595                 : 
    1596               0 :   mContextStack.AppendElement(mCurrentContext);
    1597               0 :   mCurrentContext = sc;
    1598               0 :   return NS_OK;
    1599                 : }
    1600                 : 
    1601                 : NS_IMETHODIMP
    1602               0 : HTMLContentSink::EndContext(PRInt32 aPosition)
    1603                 : {
    1604               0 :   NS_PRECONDITION(mCurrentContext && aPosition > -1, "nonexistent context");
    1605                 : 
    1606               0 :   PRUint32 n = mContextStack.Length() - 1;
    1607               0 :   SinkContext* sc = mContextStack.ElementAt(n);
    1608                 : 
    1609               0 :   const SinkContext::Node &bottom = mCurrentContext->mStack[0];
    1610                 :   
    1611               0 :   NS_ASSERTION(sc->mStack[aPosition].mType == bottom.mType,
    1612                 :                "ending a wrong context");
    1613                 : 
    1614               0 :   mCurrentContext->FlushTextAndRelease();
    1615                 :   
    1616               0 :   NS_ASSERTION(bottom.mContent->GetChildCount() == bottom.mNumFlushed,
    1617                 :                "Node at base of context stack not fully flushed.");
    1618                 : 
    1619                 :   // Flushing tags before the assertion on the previous line would
    1620                 :   // undoubtedly prevent the assertion from failing, but it shouldn't
    1621                 :   // be failing anyway, FlushTags or no.  Flushing here is nevertheless
    1622                 :   // a worthwhile precaution, since we lose some information (e.g.,
    1623                 :   // mInsertionPoints) when we end the current context.
    1624               0 :   mCurrentContext->FlushTags();
    1625                 : 
    1626               0 :   sc->mStack[aPosition].mNumFlushed = bottom.mNumFlushed;
    1627                 : 
    1628               0 :   for (PRInt32 i = 0; i<mCurrentContext->mStackPos; i++) {
    1629               0 :     NS_IF_RELEASE(mCurrentContext->mStack[i].mContent);
    1630                 :   }
    1631                 : 
    1632               0 :   delete [] mCurrentContext->mStack;
    1633                 : 
    1634               0 :   mCurrentContext->mStack      = nsnull;
    1635               0 :   mCurrentContext->mStackPos   = 0;
    1636               0 :   mCurrentContext->mStackSize  = 0;
    1637                 : 
    1638               0 :   delete [] mCurrentContext->mText;
    1639                 : 
    1640               0 :   mCurrentContext->mText       = nsnull;
    1641               0 :   mCurrentContext->mTextLength = 0;
    1642               0 :   mCurrentContext->mTextSize   = 0;
    1643                 : 
    1644               0 :   NS_IF_RELEASE(mCurrentContext->mSink);
    1645                 : 
    1646               0 :   delete mCurrentContext;
    1647                 : 
    1648               0 :   mCurrentContext = sc;
    1649               0 :   mContextStack.RemoveElementAt(n);
    1650               0 :   return NS_OK;
    1651                 : }
    1652                 : 
    1653                 : nsresult
    1654               0 : HTMLContentSink::CloseHTML()
    1655                 : {
    1656                 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
    1657                 :                  "HTMLContentSink::CloseHTML", 
    1658               0 :                  eHTMLTag_html, 0, this);
    1659                 : 
    1660               0 :   if (mHeadContext) {
    1661               0 :     if (mCurrentContext == mHeadContext) {
    1662               0 :       PRUint32 numContexts = mContextStack.Length();
    1663                 : 
    1664                 :       // Pop off the second html context if it's not done earlier
    1665               0 :       mCurrentContext = mContextStack.ElementAt(--numContexts);
    1666               0 :       mContextStack.RemoveElementAt(numContexts);
    1667                 :     }
    1668                 : 
    1669               0 :     NS_ASSERTION(mHeadContext->mTextLength == 0, "Losing text");
    1670                 : 
    1671               0 :     mHeadContext->End();
    1672                 : 
    1673               0 :     delete mHeadContext;
    1674               0 :     mHeadContext = nsnull;
    1675                 :   }
    1676                 : 
    1677               0 :   return NS_OK;
    1678                 : }
    1679                 : 
    1680                 : nsresult
    1681               0 : HTMLContentSink::OpenHead()
    1682                 : {
    1683               0 :   nsresult rv = OpenHeadContext();
    1684               0 :   return rv;
    1685                 : }
    1686                 : 
    1687                 : nsresult
    1688               0 : HTMLContentSink::OpenBody(const nsIParserNode& aNode)
    1689                 : {
    1690               0 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
    1691                 :                   "HTMLContentSink::OpenBody", 
    1692                 :                   eHTMLTag_body,
    1693                 :                   mCurrentContext->mStackPos, 
    1694               0 :                   this);
    1695                 : 
    1696               0 :   CloseHeadContext();  // do this just in case if the HEAD was left open!
    1697                 : 
    1698                 :   // Add attributes, if any, to the current BODY node
    1699               0 :   if (mBody) {
    1700               0 :     AddAttributes(aNode, mBody, true, true);
    1701               0 :     return NS_OK;
    1702                 :   }
    1703                 : 
    1704               0 :   nsresult rv = mCurrentContext->OpenContainer(aNode);
    1705                 : 
    1706               0 :   if (NS_FAILED(rv)) {
    1707               0 :     return rv;
    1708                 :   }
    1709                 : 
    1710               0 :   mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent;
    1711                 : 
    1712               0 :   if (mCurrentContext->mStackPos > 1) {
    1713               0 :     PRInt32 parentIndex    = mCurrentContext->mStackPos - 2;
    1714               0 :     nsGenericHTMLElement *parent = mCurrentContext->mStack[parentIndex].mContent;
    1715               0 :     PRInt32 numFlushed     = mCurrentContext->mStack[parentIndex].mNumFlushed;
    1716               0 :     PRInt32 childCount = parent->GetChildCount();
    1717               0 :     NS_ASSERTION(numFlushed < childCount, "Already notified on the body?");
    1718                 :     
    1719                 :     PRInt32 insertionPoint =
    1720               0 :       mCurrentContext->mStack[parentIndex].mInsertionPoint;
    1721                 : 
    1722                 :     // XXX: I have yet to see a case where numFlushed is non-zero and
    1723                 :     // insertionPoint is not -1, but this code will try to handle
    1724                 :     // those cases too.
    1725                 : 
    1726               0 :     PRUint32 oldUpdates = mUpdatesInNotification;
    1727               0 :     mUpdatesInNotification = 0;
    1728               0 :     if (insertionPoint != -1) {
    1729               0 :       NotifyInsert(parent, mBody, insertionPoint - 1);
    1730                 :     } else {
    1731               0 :       NotifyAppend(parent, numFlushed);
    1732                 :     }
    1733               0 :     mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
    1734               0 :     if (mUpdatesInNotification > 1) {
    1735               0 :       UpdateChildCounts();
    1736                 :     }
    1737               0 :     mUpdatesInNotification = oldUpdates;
    1738                 :   }
    1739                 : 
    1740               0 :   StartLayout(false);
    1741                 : 
    1742               0 :   return NS_OK;
    1743                 : }
    1744                 : 
    1745                 : nsresult
    1746               0 : HTMLContentSink::CloseBody()
    1747                 : {
    1748               0 :   SINK_TRACE_NODE(SINK_TRACE_CALLS,
    1749                 :                   "HTMLContentSink::CloseBody", 
    1750                 :                   eHTMLTag_body,
    1751                 :                   mCurrentContext->mStackPos - 1, 
    1752               0 :                   this);
    1753                 : 
    1754                 :   bool didFlush;
    1755               0 :   nsresult rv = mCurrentContext->FlushTextAndRelease(&didFlush);
    1756               0 :   if (NS_FAILED(rv)) {
    1757               0 :     return rv;
    1758                 :   }
    1759                 : 
    1760                 :   // Flush out anything that's left
    1761               0 :   SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1762                 :              ("HTMLContentSink::CloseBody: layout final body content"));
    1763                 : 
    1764               0 :   mCurrentContext->FlushTags();
    1765               0 :   mCurrentContext->CloseContainer(eHTMLTag_body);
    1766                 : 
    1767               0 :   return NS_OK;
    1768                 : }
    1769                 : 
    1770                 : NS_IMETHODIMP
    1771               0 : HTMLContentSink::IsEnabled(PRInt32 aTag, bool* aReturn)
    1772                 : {
    1773               0 :   nsHTMLTag theHTMLTag = nsHTMLTag(aTag);
    1774                 : 
    1775               0 :   if (theHTMLTag == eHTMLTag_script) {
    1776               0 :     *aReturn = mScriptEnabled;
    1777               0 :   } else if (theHTMLTag == eHTMLTag_frameset) {
    1778               0 :     *aReturn = mFramesEnabled;
    1779                 :   } else {
    1780               0 :     *aReturn = false;
    1781                 :   }
    1782                 : 
    1783               0 :   return NS_OK;
    1784                 : }
    1785                 : 
    1786                 : NS_IMETHODIMP
    1787               0 : HTMLContentSink::OpenContainer(const nsIParserNode& aNode)
    1788                 : {
    1789               0 :   nsresult rv = NS_OK;
    1790                 : 
    1791               0 :   switch (aNode.GetNodeType()) {
    1792                 :     case eHTMLTag_frameset:
    1793               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
    1794                 :       rv = NS_ERROR_NOT_IMPLEMENTED;
    1795                 :       break;
    1796                 :     case eHTMLTag_head:
    1797               0 :       rv = OpenHeadContext();
    1798               0 :       if (NS_SUCCEEDED(rv)) {
    1799               0 :         rv = AddAttributes(aNode, mHead, true, mHaveSeenHead);
    1800               0 :         mHaveSeenHead = true;
    1801                 :       }
    1802               0 :       break;
    1803                 :     case eHTMLTag_body:
    1804               0 :       rv = OpenBody(aNode);
    1805               0 :       break;
    1806                 :     case eHTMLTag_html:
    1807               0 :       if (mRoot) {
    1808                 :         // If we've already hit this code once, need to check for
    1809                 :         // already-present attributes on the root.
    1810               0 :         AddAttributes(aNode, mRoot, true, mNotifiedRootInsertion);
    1811               0 :         if (!mNotifiedRootInsertion) {
    1812               0 :           NotifyRootInsertion();
    1813                 :         }
    1814               0 :         ProcessOfflineManifest(mRoot);
    1815                 :       }
    1816               0 :       break;
    1817                 :     case eHTMLTag_form:
    1818               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
    1819                 :       rv = NS_ERROR_NOT_IMPLEMENTED;
    1820                 :       break;
    1821                 :     default:
    1822               0 :       rv = mCurrentContext->OpenContainer(aNode);
    1823               0 :       break;
    1824                 :   }
    1825                 : 
    1826               0 :   return rv;
    1827                 : }
    1828                 : 
    1829                 : NS_IMETHODIMP
    1830               0 : HTMLContentSink::CloseContainer(const eHTMLTags aTag)
    1831                 : {
    1832               0 :   nsresult rv = NS_OK;
    1833                 : 
    1834               0 :   switch (aTag) {
    1835                 :     case eHTMLTag_frameset:
    1836               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
    1837                 :       rv = NS_ERROR_NOT_IMPLEMENTED;
    1838                 :       break;
    1839                 :     case eHTMLTag_head:
    1840               0 :       CloseHeadContext();
    1841               0 :       break;
    1842                 :     case eHTMLTag_body:
    1843               0 :       rv = CloseBody();
    1844               0 :       break;
    1845                 :     case eHTMLTag_html:
    1846               0 :       rv = CloseHTML();
    1847               0 :       break;
    1848                 :     case eHTMLTag_form:
    1849               0 :       MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
    1850                 :       rv = NS_ERROR_NOT_IMPLEMENTED;
    1851                 :       break;
    1852                 :     default:
    1853               0 :       rv = mCurrentContext->CloseContainer(aTag);
    1854               0 :       break;
    1855                 :   }
    1856                 : 
    1857               0 :   return rv;
    1858                 : }
    1859                 : 
    1860                 : NS_IMETHODIMP
    1861               0 : HTMLContentSink::CloseMalformedContainer(const eHTMLTags aTag)
    1862                 : {
    1863               0 :   return mCurrentContext->CloseContainer(aTag);
    1864                 : }
    1865                 : 
    1866                 : NS_IMETHODIMP
    1867               0 : HTMLContentSink::AddLeaf(const nsIParserNode& aNode)
    1868                 : {
    1869                 :   nsresult rv;
    1870                 : 
    1871               0 :   nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
    1872               0 :   switch (nodeType) {
    1873                 :   case eHTMLTag_link:
    1874               0 :     rv = NS_ERROR_NOT_IMPLEMENTED;
    1875               0 :     MOZ_NOT_REACHED("Must not use HTMLContentSink for links.");
    1876                 : 
    1877                 :     break;
    1878                 :   default:
    1879               0 :     rv = mCurrentContext->AddLeaf(aNode);
    1880                 : 
    1881                 :     break;
    1882                 :   }
    1883                 : 
    1884               0 :   return rv;
    1885                 : }
    1886                 : 
    1887                 : NS_IMETHODIMP
    1888               0 : HTMLContentSink::DidProcessTokens(void)
    1889                 : {
    1890               0 :   return NS_OK;
    1891                 : }
    1892                 : 
    1893                 : NS_IMETHODIMP
    1894               0 : HTMLContentSink::WillProcessAToken(void)
    1895                 : {
    1896               0 :   return NS_OK;
    1897                 : }
    1898                 : 
    1899                 : NS_IMETHODIMP
    1900               0 : HTMLContentSink::DidProcessAToken(void)
    1901                 : {
    1902               0 :   return DidProcessATokenImpl();
    1903                 : }
    1904                 : 
    1905                 : NS_IMETHODIMP
    1906               0 : HTMLContentSink::WillInterrupt()
    1907                 : {
    1908               0 :   return WillInterruptImpl();
    1909                 : }
    1910                 : 
    1911                 : NS_IMETHODIMP
    1912               0 : HTMLContentSink::WillResume()
    1913                 : {
    1914               0 :   return WillResumeImpl();
    1915                 : }
    1916                 : 
    1917                 : nsresult
    1918               0 : HTMLContentSink::OpenHeadContext()
    1919                 : {
    1920               0 :   if (mCurrentContext && mCurrentContext->IsCurrentContainer(eHTMLTag_head))
    1921               0 :     return NS_OK;
    1922                 : 
    1923                 :   // Flush everything in the current context so that we don't have
    1924                 :   // to worry about insertions resulting in inconsistent frame creation.
    1925                 :   //
    1926                 :   // Try to do this only if needed (costly), i.e., only if we are sure
    1927                 :   // we are changing contexts from some other context to the head.
    1928                 :   //
    1929                 :   // PERF: This call causes approximately a 2% slowdown in page load time
    1930                 :   // according to jrgm's page load tests, but seems to be a necessary evil
    1931               0 :   if (mCurrentContext && (mCurrentContext != mHeadContext)) {
    1932               0 :     mCurrentContext->FlushTags();
    1933                 :   }
    1934                 : 
    1935               0 :   if (!mHeadContext) {
    1936               0 :     mHeadContext = new SinkContext(this);
    1937               0 :     NS_ENSURE_TRUE(mHeadContext, NS_ERROR_OUT_OF_MEMORY);
    1938                 : 
    1939               0 :     nsresult rv = mHeadContext->Begin(eHTMLTag_head, mHead, 0, -1);
    1940               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1941                 :   }
    1942                 : 
    1943               0 :   mContextStack.AppendElement(mCurrentContext);
    1944               0 :   mCurrentContext = mHeadContext;
    1945                 : 
    1946               0 :   return NS_OK;
    1947                 : }
    1948                 : 
    1949                 : void
    1950               0 : HTMLContentSink::CloseHeadContext()
    1951                 : {
    1952               0 :   if (mCurrentContext) {
    1953               0 :     if (!mCurrentContext->IsCurrentContainer(eHTMLTag_head))
    1954               0 :       return;
    1955                 : 
    1956               0 :     mCurrentContext->FlushTextAndRelease();
    1957               0 :     mCurrentContext->FlushTags();
    1958                 :   }
    1959                 : 
    1960               0 :   if (!mContextStack.IsEmpty())
    1961                 :   {
    1962               0 :     PRUint32 n = mContextStack.Length() - 1;
    1963               0 :     mCurrentContext = mContextStack.ElementAt(n);
    1964               0 :     mContextStack.RemoveElementAt(n);
    1965                 :   }
    1966                 : }
    1967                 : 
    1968                 : #ifdef DEBUG
    1969                 : void
    1970               0 : HTMLContentSink::ForceReflow()
    1971                 : {
    1972               0 :   mCurrentContext->FlushTags();
    1973               0 : }
    1974                 : #endif
    1975                 : 
    1976                 : void
    1977               0 : HTMLContentSink::NotifyInsert(nsIContent* aContent,
    1978                 :                               nsIContent* aChildContent,
    1979                 :                               PRInt32 aIndexInContainer)
    1980                 : {
    1981               0 :   if (aContent && aContent->GetCurrentDoc() != mDocument) {
    1982                 :     // aContent is not actually in our document anymore.... Just bail out of
    1983                 :     // here; notifying on our document for this insert would be wrong.
    1984               0 :     return;
    1985                 :   }
    1986                 : 
    1987               0 :   mInNotification++;
    1988                 : 
    1989                 :   {
    1990                 :     // Scope so we call EndUpdate before we decrease mInNotification
    1991               0 :     MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
    1992                 :     nsNodeUtils::ContentInserted(NODE_FROM(aContent, mDocument),
    1993               0 :                                  aChildContent, aIndexInContainer);
    1994               0 :     mLastNotificationTime = PR_Now();
    1995                 :   }
    1996                 : 
    1997               0 :   mInNotification--;
    1998                 : }
    1999                 : 
    2000                 : void
    2001               0 : HTMLContentSink::NotifyRootInsertion()
    2002                 : {
    2003               0 :   NS_PRECONDITION(!mNotifiedRootInsertion, "Double-notifying on root?");
    2004               0 :   NS_ASSERTION(!mLayoutStarted,
    2005                 :                "How did we start layout without notifying on root?");
    2006                 :   // Now make sure to notify that we have now inserted our root.  If
    2007                 :   // there has been no initial reflow yet it'll be a no-op, but if
    2008                 :   // there has been one we need this to get its frames constructed.
    2009                 :   // Note that if mNotifiedRootInsertion is true we don't notify here,
    2010                 :   // since that just means there are multiple <html> tags in the
    2011                 :   // document; in those cases we just want to put all the attrs on one
    2012                 :   // tag.
    2013               0 :   mNotifiedRootInsertion = true;
    2014               0 :   PRInt32 index = mDocument->IndexOf(mRoot);
    2015               0 :   NS_ASSERTION(index != -1, "mRoot not child of document?");
    2016               0 :   NotifyInsert(nsnull, mRoot, index);
    2017                 : 
    2018                 :   // Now update the notification information in all our
    2019                 :   // contexts, since we just inserted the root and notified on
    2020                 :   // our whole tree
    2021               0 :   UpdateChildCounts();
    2022               0 : }
    2023                 : 
    2024                 : bool
    2025               0 : HTMLContentSink::IsMonolithicContainer(nsHTMLTag aTag)
    2026                 : {
    2027               0 :   if (aTag == eHTMLTag_tr     ||
    2028                 :       aTag == eHTMLTag_select ||
    2029                 :       aTag == eHTMLTag_applet ||
    2030                 :       aTag == eHTMLTag_object) {
    2031               0 :     return true;
    2032                 :   }
    2033                 : 
    2034               0 :   return false;
    2035                 : }
    2036                 : 
    2037                 : void
    2038               0 : HTMLContentSink::UpdateChildCounts()
    2039                 : {
    2040               0 :   PRUint32 numContexts = mContextStack.Length();
    2041               0 :   for (PRUint32 i = 0; i < numContexts; i++) {
    2042               0 :     SinkContext* sc = mContextStack.ElementAt(i);
    2043                 : 
    2044               0 :     sc->UpdateChildCounts();
    2045                 :   }
    2046                 : 
    2047               0 :   mCurrentContext->UpdateChildCounts();
    2048               0 : }
    2049                 : 
    2050                 : void
    2051               0 : HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
    2052                 : {
    2053                 :   // Only flush tags if we're not doing the notification ourselves
    2054                 :   // (since we aren't reentrant)
    2055               0 :   if (!mInNotification) {
    2056                 :     // Only flush if we're still a document observer (so that our child counts
    2057                 :     // should be correct).
    2058               0 :     if (mIsDocumentObserver) {
    2059               0 :       if (aType >= Flush_ContentAndNotify) {
    2060               0 :         FlushTags();
    2061                 :       }
    2062               0 :       else if (mCurrentContext) {
    2063               0 :         mCurrentContext->FlushText();
    2064                 :       }
    2065                 :     }
    2066               0 :     if (aType >= Flush_InterruptibleLayout) {
    2067                 :       // Make sure that layout has started so that the reflow flush
    2068                 :       // will actually happen.
    2069               0 :       StartLayout(true);
    2070                 :     }
    2071                 :   }
    2072               0 : }
    2073                 : 
    2074                 : nsresult
    2075               0 : HTMLContentSink::FlushTags()
    2076                 : {
    2077               0 :   if (!mNotifiedRootInsertion) {
    2078               0 :     NotifyRootInsertion();
    2079               0 :     return NS_OK;
    2080                 :   }
    2081                 :   
    2082               0 :   return mCurrentContext ? mCurrentContext->FlushTags() : NS_OK;
    2083                 : }
    2084                 : 
    2085                 : NS_IMETHODIMP
    2086               0 : HTMLContentSink::SetDocumentCharset(nsACString& aCharset)
    2087                 : {
    2088               0 :   if (mDocShell) {
    2089                 :     // the following logic to get muCV is copied from
    2090                 :     // nsHTMLDocument::StartDocumentLoad
    2091                 :     // We need to call muCV->SetPrevDocCharacterSet here in case
    2092                 :     // the charset is detected by parser DetectMetaTag
    2093               0 :     nsCOMPtr<nsIMarkupDocumentViewer> muCV;
    2094               0 :     nsCOMPtr<nsIContentViewer> cv;
    2095               0 :     mDocShell->GetContentViewer(getter_AddRefs(cv));
    2096               0 :     if (cv) {
    2097               0 :        muCV = do_QueryInterface(cv);
    2098                 :     } else {
    2099                 :       // in this block of code, if we get an error result, we return
    2100                 :       // it but if we get a null pointer, that's perfectly legal for
    2101                 :       // parent and parentContentViewer
    2102                 : 
    2103                 :       nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
    2104               0 :         do_QueryInterface(mDocShell);
    2105               0 :       NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
    2106                 : 
    2107               0 :       nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    2108               0 :       docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2109                 : 
    2110               0 :       nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
    2111               0 :       if (parent) {
    2112               0 :         nsCOMPtr<nsIContentViewer> parentContentViewer;
    2113                 :         nsresult rv =
    2114               0 :           parent->GetContentViewer(getter_AddRefs(parentContentViewer));
    2115               0 :         if (NS_SUCCEEDED(rv) && parentContentViewer) {
    2116               0 :           muCV = do_QueryInterface(parentContentViewer);
    2117                 :         }
    2118                 :       }
    2119                 :     }
    2120                 : 
    2121               0 :     if (muCV) {
    2122               0 :       muCV->SetPrevDocCharacterSet(aCharset);
    2123                 :     }
    2124                 :   }
    2125                 : 
    2126               0 :   if (mDocument) {
    2127               0 :     mDocument->SetDocumentCharacterSet(aCharset);
    2128                 :   }
    2129                 : 
    2130               0 :   return NS_OK;
    2131                 : }
    2132                 : 
    2133                 : nsISupports *
    2134               0 : HTMLContentSink::GetTarget()
    2135                 : {
    2136               0 :   return mDocument;
    2137                 : }
    2138                 : 
    2139                 : bool
    2140               0 : HTMLContentSink::IsScriptExecuting()
    2141                 : {
    2142               0 :   return IsScriptExecutingImpl();
    2143                 : }
    2144                 : 
    2145                 : #ifdef DEBUG
    2146                 : /**
    2147                 :  *  This will dump content model into the output file.
    2148                 :  *
    2149                 :  *  @update  harishd 05/25/00
    2150                 :  *  @param
    2151                 :  *  @return  NS_OK all went well, error on failure
    2152                 :  */
    2153                 : 
    2154                 : NS_IMETHODIMP
    2155               0 : HTMLContentSink::DumpContentModel()
    2156                 : {
    2157               0 :   FILE* out = ::fopen("rtest_html.txt", "a");
    2158               0 :   if (out) {
    2159               0 :     if (mDocument) {
    2160               0 :       Element* root = mDocument->GetRootElement();
    2161               0 :       if (root) {
    2162               0 :         if (mDocumentURI) {
    2163               0 :           nsCAutoString buf;
    2164               0 :           mDocumentURI->GetSpec(buf);
    2165               0 :           fputs(buf.get(), out);
    2166                 :         }
    2167                 : 
    2168               0 :         fputs(";", out);
    2169               0 :         root->DumpContent(out, 0, false);
    2170               0 :         fputs(";\n", out);
    2171                 :       }
    2172                 :     }
    2173                 : 
    2174               0 :     fclose(out);
    2175                 :   }
    2176                 : 
    2177               0 :   return NS_OK;
    2178            4392 : }
    2179                 : #endif
    2180                 : 

Generated by: LCOV version 1.7