LCOV - code coverage report
Current view: directory - parser/html - nsHtml5Parser.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 327 2 0.6 %
Date: 2012-06-02 Functions: 44 2 4.5 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set sw=2 ts=2 et tw=79: */
       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                 :  *   Henri Sivonen <hsivonen@iki.fi>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsCompatibility.h"
      42                 : #include "nsScriptLoader.h"
      43                 : #include "nsNetUtil.h"
      44                 : #include "nsIStyleSheetLinkingElement.h"
      45                 : #include "nsIWebShellServices.h"
      46                 : #include "nsIDocShell.h"
      47                 : #include "nsEncoderDecoderUtils.h"
      48                 : #include "nsContentUtils.h"
      49                 : #include "nsICharsetDetector.h"
      50                 : #include "nsIScriptElement.h"
      51                 : #include "nsIMarkupDocumentViewer.h"
      52                 : #include "nsIDocShellTreeItem.h"
      53                 : #include "nsIContentViewer.h"
      54                 : #include "nsIScriptGlobalObjectOwner.h"
      55                 : #include "nsIScriptSecurityManager.h"
      56                 : #include "nsHtml5DocumentMode.h"
      57                 : #include "nsHtml5Tokenizer.h"
      58                 : #include "nsHtml5UTF16Buffer.h"
      59                 : #include "nsHtml5TreeBuilder.h"
      60                 : #include "nsHtml5Parser.h"
      61                 : #include "nsHtml5AtomTable.h"
      62                 : #include "nsIDOMDocumentFragment.h"
      63                 : #include "nsHtml5DependentUTF16Buffer.h"
      64                 : 
      65               0 : NS_INTERFACE_TABLE_HEAD(nsHtml5Parser)
      66               0 :   NS_INTERFACE_TABLE2(nsHtml5Parser, nsIParser, nsISupportsWeakReference)
      67               0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHtml5Parser)
      68               0 : NS_INTERFACE_MAP_END
      69                 : 
      70               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHtml5Parser)
      71               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHtml5Parser)
      72                 : 
      73            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHtml5Parser)
      74                 : 
      75               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5Parser)
      76               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mExecutor,
      77                 :                                                        nsIContentSink)
      78               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mStreamParser,
      79                 :                                                        nsIStreamListener)
      80               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      81                 : 
      82               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHtml5Parser)
      83               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mExecutor)
      84               0 :   tmp->DropStreamParser();
      85               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      86                 : 
      87               0 : nsHtml5Parser::nsHtml5Parser()
      88               0 :   : mFirstBuffer(new nsHtml5OwningUTF16Buffer((void*)nsnull))
      89                 :   , mLastBuffer(mFirstBuffer)
      90                 :   , mExecutor(new nsHtml5TreeOpExecutor())
      91               0 :   , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor, nsnull))
      92               0 :   , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder, false))
      93               0 :   , mRootContextLineNumber(1)
      94                 : {
      95               0 :   mAtomTable.Init(); // we aren't checking for OOM anyway...
      96               0 :   mTokenizer->setInterner(&mAtomTable);
      97                 :   // There's a zeroing operator new for everything else
      98               0 : }
      99                 : 
     100               0 : nsHtml5Parser::~nsHtml5Parser()
     101                 : {
     102               0 :   mTokenizer->end();
     103               0 :   if (mDocWriteSpeculativeTokenizer) {
     104               0 :     mDocWriteSpeculativeTokenizer->end();
     105                 :   }
     106               0 : }
     107                 : 
     108                 : NS_IMETHODIMP_(void)
     109               0 : nsHtml5Parser::SetContentSink(nsIContentSink* aSink)
     110                 : {
     111               0 :   NS_ASSERTION(aSink == static_cast<nsIContentSink*> (mExecutor), 
     112                 :                "Attempt to set a foreign sink.");
     113               0 : }
     114                 : 
     115                 : NS_IMETHODIMP_(nsIContentSink*)
     116               0 : nsHtml5Parser::GetContentSink()
     117                 : {
     118               0 :   return static_cast<nsIContentSink*> (mExecutor);
     119                 : }
     120                 : 
     121                 : NS_IMETHODIMP_(void)
     122               0 : nsHtml5Parser::GetCommand(nsCString& aCommand)
     123                 : {
     124               0 :   aCommand.Assign("view");
     125               0 : }
     126                 : 
     127                 : NS_IMETHODIMP_(void)
     128               0 : nsHtml5Parser::SetCommand(const char* aCommand)
     129                 : {
     130               0 :   NS_ASSERTION(!strcmp(aCommand, "view") ||
     131                 :                !strcmp(aCommand, "view-source") ||
     132                 :                !strcmp(aCommand, "external-resource") ||
     133                 :                !strcmp(aCommand, kLoadAsData),
     134                 :                "Unsupported parser command");
     135               0 : }
     136                 : 
     137                 : NS_IMETHODIMP_(void)
     138               0 : nsHtml5Parser::SetCommand(eParserCommands aParserCommand)
     139                 : {
     140               0 :   NS_ASSERTION(aParserCommand == eViewNormal, 
     141                 :                "Parser command was not eViewNormal.");
     142               0 : }
     143                 : 
     144                 : NS_IMETHODIMP_(void)
     145               0 : nsHtml5Parser::SetDocumentCharset(const nsACString& aCharset,
     146                 :                                   PRInt32 aCharsetSource)
     147                 : {
     148               0 :   NS_PRECONDITION(!mExecutor->HasStarted(),
     149                 :                   "Document charset set too late.");
     150               0 :   NS_PRECONDITION(mStreamParser, "Setting charset on a script-only parser.");
     151               0 :   nsCAutoString trimmed;
     152               0 :   trimmed.Assign(aCharset);
     153               0 :   trimmed.Trim(" \t\r\n\f");
     154               0 :   mStreamParser->SetDocumentCharset(trimmed, aCharsetSource);
     155                 :   mExecutor->SetDocumentCharsetAndSource(trimmed,
     156               0 :                                          aCharsetSource);
     157               0 : }
     158                 : 
     159                 : NS_IMETHODIMP
     160               0 : nsHtml5Parser::GetChannel(nsIChannel** aChannel)
     161                 : {
     162               0 :   if (mStreamParser) {
     163               0 :     return mStreamParser->GetChannel(aChannel);
     164                 :   } else {
     165               0 :     return NS_ERROR_NOT_AVAILABLE;
     166                 :   }
     167                 : }
     168                 : 
     169                 : NS_IMETHODIMP
     170               0 : nsHtml5Parser::GetDTD(nsIDTD** aDTD)
     171                 : {
     172               0 :   *aDTD = nsnull;
     173               0 :   return NS_OK;
     174                 : }
     175                 : 
     176                 : nsIStreamListener*
     177               0 : nsHtml5Parser::GetStreamListener()
     178                 : {
     179               0 :   return mStreamParser;
     180                 : }
     181                 : 
     182                 : NS_IMETHODIMP
     183               0 : nsHtml5Parser::ContinueInterruptedParsing()
     184                 : {
     185               0 :   NS_NOTREACHED("Don't call. For interface compat only.");
     186               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     187                 : }
     188                 : 
     189                 : NS_IMETHODIMP_(void)
     190               0 : nsHtml5Parser::BlockParser()
     191                 : {
     192               0 :   mBlocked = true;
     193               0 : }
     194                 : 
     195                 : NS_IMETHODIMP_(void)
     196               0 : nsHtml5Parser::UnblockParser()
     197                 : {
     198               0 :   mBlocked = false;
     199               0 :   mExecutor->ContinueInterruptedParsingAsync();
     200               0 : }
     201                 : 
     202                 : NS_IMETHODIMP_(void)
     203               0 : nsHtml5Parser::ContinueInterruptedParsingAsync()
     204                 : {
     205               0 :   mExecutor->ContinueInterruptedParsingAsync();
     206               0 : }
     207                 : 
     208                 : NS_IMETHODIMP_(bool)
     209               0 : nsHtml5Parser::IsParserEnabled()
     210                 : {
     211               0 :   return !mBlocked;
     212                 : }
     213                 : 
     214                 : NS_IMETHODIMP_(bool)
     215               0 : nsHtml5Parser::IsComplete()
     216                 : {
     217               0 :   return mExecutor->IsComplete();
     218                 : }
     219                 : 
     220                 : NS_IMETHODIMP
     221               0 : nsHtml5Parser::Parse(nsIURI* aURL,
     222                 :                      nsIRequestObserver* aObserver,
     223                 :                      void* aKey, // legacy; ignored
     224                 :                      nsDTDMode aMode) // legacy; ignored
     225                 : {
     226                 :   /*
     227                 :    * Do NOT cause WillBuildModel to be called synchronously from here!
     228                 :    * The document won't be ready for it until OnStartRequest!
     229                 :    */
     230               0 :   NS_PRECONDITION(!mExecutor->HasStarted(), 
     231                 :                   "Tried to start parse without initializing the parser.");
     232               0 :   NS_PRECONDITION(mStreamParser, 
     233                 :                   "Can't call this Parse() variant on script-created parser");
     234               0 :   mStreamParser->SetObserver(aObserver);
     235               0 :   mStreamParser->SetViewSourceTitle(aURL); // In case we're viewing source
     236               0 :   mExecutor->SetStreamParser(mStreamParser);
     237               0 :   mExecutor->SetParser(this);
     238               0 :   return NS_OK;
     239                 : }
     240                 : 
     241                 : NS_IMETHODIMP
     242               0 : nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
     243                 :                      void* aKey,
     244                 :                      const nsACString& aContentType,
     245                 :                      bool aLastCall,
     246                 :                      nsDTDMode aMode) // ignored
     247                 : {
     248               0 :   if (mExecutor->IsBroken()) {
     249               0 :     return NS_ERROR_OUT_OF_MEMORY;
     250                 :   }
     251               0 :   if (aSourceBuffer.Length() > PR_INT32_MAX) {
     252               0 :     mExecutor->MarkAsBroken();
     253               0 :     return NS_ERROR_OUT_OF_MEMORY;
     254                 :   }
     255                 : 
     256                 :   // Maintain a reference to ourselves so we don't go away
     257                 :   // till we're completely done. The old parser grips itself in this method.
     258               0 :   nsCOMPtr<nsIParser> kungFuDeathGrip(this);
     259                 :   
     260                 :   // Gripping the other objects just in case, since the other old grip
     261                 :   // required grips to these, too.
     262               0 :   nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip(mStreamParser);
     263               0 :   nsRefPtr<nsHtml5TreeOpExecutor> treeOpKungFuDeathGrip(mExecutor);
     264                 : 
     265               0 :   if (!mExecutor->HasStarted()) {
     266               0 :     NS_ASSERTION(!mStreamParser,
     267                 :                  "Had stream parser but document.write started life cycle.");
     268                 :     // This is the first document.write() on a document.open()ed document
     269               0 :     mExecutor->SetParser(this);
     270               0 :     mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled());
     271               0 :     mTokenizer->start();
     272               0 :     mExecutor->Start();
     273               0 :     if (!aContentType.EqualsLiteral("text/html")) {
     274               0 :       mTreeBuilder->StartPlainText();
     275               0 :       mTokenizer->StartPlainText();
     276                 :     }
     277                 :     /*
     278                 :      * If you move the following line, be very careful not to cause 
     279                 :      * WillBuildModel to be called before the document has had its 
     280                 :      * script global object set.
     281                 :      */
     282               0 :     mExecutor->WillBuildModel(eDTDMode_unknown);
     283                 :   }
     284                 : 
     285                 :   // Return early if the parser has processed EOF
     286               0 :   if (mExecutor->IsComplete()) {
     287               0 :     return NS_OK;
     288                 :   }
     289                 : 
     290               0 :   if (aLastCall && aSourceBuffer.IsEmpty() && !aKey) {
     291                 :     // document.close()
     292               0 :     NS_ASSERTION(!mStreamParser,
     293                 :                  "Had stream parser but got document.close().");
     294               0 :     if (mDocumentClosed) {
     295                 :       // already closed
     296               0 :       return NS_OK;
     297                 :     }
     298               0 :     mDocumentClosed = true;
     299               0 :     if (!mBlocked && !mInDocumentWrite) {
     300               0 :       ParseUntilBlocked();
     301                 :     }
     302               0 :     return NS_OK;
     303                 :   }
     304                 : 
     305                 :   // If we got this far, we are dealing with a document.write or
     306                 :   // document.writeln call--not document.close().
     307                 : 
     308               0 :   NS_ASSERTION(IsInsertionPointDefined(),
     309                 :                "Doc.write reached parser with undefined insertion point.");
     310                 : 
     311               0 :   NS_ASSERTION(!(mStreamParser && !aKey),
     312                 :                "Got a null key in a non-script-created parser");
     313                 : 
     314                 :   // XXX is this optimization bogus?
     315               0 :   if (aSourceBuffer.IsEmpty()) {
     316               0 :     return NS_OK;
     317                 :   }
     318                 : 
     319                 :   // This guard is here to prevent document.close from tokenizing synchronously
     320                 :   // while a document.write (that wrote the script that called document.close!)
     321                 :   // is still on the call stack.
     322               0 :   mozilla::AutoRestore<bool> guard(mInDocumentWrite);
     323               0 :   mInDocumentWrite = true;
     324                 : 
     325                 :   // The script is identified by aKey. If there's nothing in the buffer
     326                 :   // chain for that key, we'll insert at the head of the queue.
     327                 :   // When the script leaves something in the queue, a zero-length
     328                 :   // key-holder "buffer" is inserted in the queue. If the same script
     329                 :   // leaves something in the chain again, it will be inserted immediately
     330                 :   // before the old key holder belonging to the same script.
     331                 :   //
     332                 :   // We don't do the actual data insertion yet in the hope that the data gets
     333                 :   // tokenized and there no data or less data to copy to the heap after
     334                 :   // tokenization. Also, this way, we avoid inserting one empty data buffer
     335                 :   // per document.write, which matters for performance when the parser isn't
     336                 :   // blocked and a badly-authored script calls document.write() once per
     337                 :   // input character. (As seen in a benchmark!)
     338                 :   //
     339                 :   // The insertion into the input stream happens conceptually before anything
     340                 :   // gets tokenized. To make sure multi-level document.write works right,
     341                 :   // it's necessary to establish the location of our parser key up front
     342                 :   // in case this is the first write with this key.
     343                 :   //
     344                 :   // In a document.open() case, the first write level has a null key, so that
     345                 :   // case is handled separately, because normal buffers containing data
     346                 :   // have null keys.
     347                 : 
     348                 :   // These don't need to be owning references, because they always point to
     349                 :   // the buffer queue and buffers can't be removed from the buffer queue
     350                 :   // before document.write() returns. The buffer queue clean-up happens the
     351                 :   // next time ParseUntilBlocked() is called.
     352                 :   // However, they are made owning just in case the reasoning above is flawed
     353                 :   // and a flaw would lead to worse problems with plain pointers. If this
     354                 :   // turns out to be a perf problem, it's worthwhile to consider making
     355                 :   // prevSearchbuf a plain pointer again.
     356               0 :   nsRefPtr<nsHtml5OwningUTF16Buffer> prevSearchBuf;
     357               0 :   nsRefPtr<nsHtml5OwningUTF16Buffer> firstLevelMarker;
     358                 : 
     359               0 :   if (aKey) {
     360               0 :     if (mFirstBuffer == mLastBuffer) {
     361               0 :       nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey);
     362               0 :       keyHolder->next = mLastBuffer;
     363               0 :       mFirstBuffer = keyHolder;
     364               0 :     } else if (mFirstBuffer->key != aKey) {
     365               0 :       prevSearchBuf = mFirstBuffer;
     366               0 :       for (;;) {
     367               0 :         if (prevSearchBuf->next == mLastBuffer) {
     368                 :           // key was not found
     369                 :           nsHtml5OwningUTF16Buffer* keyHolder =
     370               0 :             new nsHtml5OwningUTF16Buffer(aKey);
     371               0 :           keyHolder->next = mFirstBuffer;
     372               0 :           mFirstBuffer = keyHolder;
     373               0 :           prevSearchBuf = nsnull;
     374               0 :           break;
     375                 :         }
     376               0 :         if (prevSearchBuf->next->key == aKey) {
     377                 :           // found a key holder
     378               0 :           break;
     379                 :         }
     380               0 :         prevSearchBuf = prevSearchBuf->next;
     381                 :       }
     382                 :     } // else mFirstBuffer is the keyholder
     383                 : 
     384                 :     // prevSearchBuf is the previous buffer before the keyholder or null if
     385                 :     // there isn't one.
     386                 :   } else {
     387                 :     // We have a first-level write in the document.open() case. We insert
     388                 :     // before mLastBuffer. We need to put a marker there, because otherwise
     389                 :     // additional document.writes from nested event loops would insert in the
     390                 :     // wrong place. Sigh.
     391               0 :     firstLevelMarker = new nsHtml5OwningUTF16Buffer((void*)nsnull);
     392               0 :     if (mFirstBuffer == mLastBuffer) {
     393               0 :       firstLevelMarker->next = mLastBuffer;
     394               0 :       mFirstBuffer = firstLevelMarker;
     395                 :     } else {
     396               0 :       prevSearchBuf = mFirstBuffer;
     397               0 :       while (prevSearchBuf->next != mLastBuffer) {
     398               0 :         prevSearchBuf = prevSearchBuf->next;
     399                 :       }
     400               0 :       firstLevelMarker->next = mLastBuffer;
     401               0 :       prevSearchBuf->next = firstLevelMarker;
     402                 :     }
     403                 :   }
     404                 : 
     405               0 :   nsHtml5DependentUTF16Buffer stackBuffer(aSourceBuffer);
     406                 : 
     407               0 :   while (!mBlocked && stackBuffer.hasMore()) {
     408               0 :     stackBuffer.adjust(mLastWasCR);
     409               0 :     mLastWasCR = false;
     410               0 :     if (stackBuffer.hasMore()) {
     411                 :       PRInt32 lineNumberSave;
     412               0 :       bool inRootContext = (!mStreamParser && !aKey);
     413               0 :       if (inRootContext) {
     414               0 :         mTokenizer->setLineNumber(mRootContextLineNumber);
     415                 :       } else {
     416                 :         // we aren't the root context, so save the line number on the
     417                 :         // *stack* so that we can restore it.
     418               0 :         lineNumberSave = mTokenizer->getLineNumber();
     419                 :       }
     420                 : 
     421               0 :       mLastWasCR = mTokenizer->tokenizeBuffer(&stackBuffer);
     422                 : 
     423               0 :       if (inRootContext) {
     424               0 :         mRootContextLineNumber = mTokenizer->getLineNumber();
     425                 :       } else {
     426               0 :         mTokenizer->setLineNumber(lineNumberSave);
     427                 :       }
     428                 : 
     429               0 :       if (mTreeBuilder->HasScript()) {
     430               0 :         mTreeBuilder->Flush(); // Move ops to the executor
     431               0 :         mExecutor->FlushDocumentWrite(); // run the ops
     432                 :         // Flushing tree ops can cause all sorts of things.
     433                 :         // Return early if the parser got terminated.
     434               0 :         if (mExecutor->IsComplete()) {
     435               0 :           return NS_OK;
     436                 :         }
     437                 :       }
     438                 :       // Ignore suspension requests
     439                 :     }
     440                 :   }
     441                 : 
     442               0 :   nsRefPtr<nsHtml5OwningUTF16Buffer> heapBuffer;
     443               0 :   if (stackBuffer.hasMore()) {
     444                 :     // The buffer wasn't tokenized to completion. Create a copy of the tail
     445                 :     // on the heap.
     446               0 :     heapBuffer = stackBuffer.FalliblyCopyAsOwningBuffer();
     447               0 :     if (!heapBuffer) {
     448                 :       // Allocation failed. The parser is now broken.
     449               0 :       mExecutor->MarkAsBroken();
     450               0 :       return NS_ERROR_OUT_OF_MEMORY;
     451                 :     }
     452                 :   }
     453                 : 
     454               0 :   if (heapBuffer) {
     455                 :     // We have something to insert before the keyholder holding in the non-null
     456                 :     // aKey case and we have something to swap into firstLevelMarker in the
     457                 :     // null aKey case.
     458               0 :     if (aKey) {
     459               0 :       NS_ASSERTION(mFirstBuffer != mLastBuffer,
     460                 :         "Where's the keyholder?");
     461                 :       // the key holder is still somewhere further down the list from
     462                 :       // prevSearchBuf (which may be null)
     463               0 :       if (mFirstBuffer->key == aKey) {
     464               0 :         NS_ASSERTION(!prevSearchBuf,
     465                 :           "Non-null prevSearchBuf when mFirstBuffer is the key holder?");
     466               0 :         heapBuffer->next = mFirstBuffer;
     467               0 :         mFirstBuffer = heapBuffer;
     468                 :       } else {
     469               0 :         if (!prevSearchBuf) {
     470               0 :           prevSearchBuf = mFirstBuffer;
     471                 :         }
     472                 :         // We created a key holder earlier, so we will find it without walking
     473                 :         // past the end of the list.
     474               0 :         while (prevSearchBuf->next->key != aKey) {
     475               0 :           prevSearchBuf = prevSearchBuf->next;
     476                 :         }
     477               0 :         heapBuffer->next = prevSearchBuf->next;
     478               0 :         prevSearchBuf->next = heapBuffer;
     479                 :       }
     480                 :     } else {
     481               0 :       NS_ASSERTION(firstLevelMarker, "How come we don't have a marker.");
     482               0 :       firstLevelMarker->Swap(heapBuffer);
     483                 :     }
     484                 :   }
     485                 : 
     486               0 :   if (!mBlocked) { // buffer was tokenized to completion
     487               0 :     NS_ASSERTION(!stackBuffer.hasMore(),
     488                 :       "Buffer wasn't tokenized to completion?");
     489                 :     // Scripting semantics require a forced tree builder flush here
     490               0 :     mTreeBuilder->Flush(); // Move ops to the executor
     491               0 :     mExecutor->FlushDocumentWrite(); // run the ops
     492               0 :   } else if (stackBuffer.hasMore()) {
     493                 :     // The buffer wasn't tokenized to completion. Tokenize the untokenized
     494                 :     // content in order to preload stuff. This content will be retokenized
     495                 :     // later for normal parsing.
     496               0 :     if (!mDocWriteSpeculatorActive) {
     497               0 :       mDocWriteSpeculatorActive = true;
     498               0 :       if (!mDocWriteSpeculativeTreeBuilder) {
     499                 :         // Lazily initialize if uninitialized
     500                 :         mDocWriteSpeculativeTreeBuilder =
     501               0 :             new nsHtml5TreeBuilder(nsnull, mExecutor->GetStage());
     502                 :         mDocWriteSpeculativeTreeBuilder->setScriptingEnabled(
     503               0 :             mTreeBuilder->isScriptingEnabled());
     504                 :         mDocWriteSpeculativeTokenizer =
     505               0 :             new nsHtml5Tokenizer(mDocWriteSpeculativeTreeBuilder, false);
     506               0 :         mDocWriteSpeculativeTokenizer->setInterner(&mAtomTable);
     507               0 :         mDocWriteSpeculativeTokenizer->start();
     508                 :       }
     509               0 :       mDocWriteSpeculativeTokenizer->resetToDataState();
     510               0 :       mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder, &mAtomTable);
     511               0 :       mDocWriteSpeculativeLastWasCR = false;
     512                 :     }
     513                 : 
     514                 :     // Note that with multilevel document.write if we didn't just activate the
     515                 :     // speculator, it's possible that the speculator is now in the wrong state.
     516                 :     // That's OK for the sake of simplicity. The worst that can happen is
     517                 :     // that the speculative loads aren't exactly right. The content will be
     518                 :     // reparsed anyway for non-preload purposes.
     519                 : 
     520                 :     // The buffer position for subsequent non-speculative parsing now lives
     521                 :     // in heapBuffer, so it's ok to let the buffer position of stackBuffer
     522                 :     // to be overwritten and not restored below.
     523               0 :     while (stackBuffer.hasMore()) {
     524               0 :       stackBuffer.adjust(mDocWriteSpeculativeLastWasCR);
     525               0 :       if (stackBuffer.hasMore()) {
     526                 :         mDocWriteSpeculativeLastWasCR =
     527               0 :             mDocWriteSpeculativeTokenizer->tokenizeBuffer(&stackBuffer);
     528                 :       }
     529                 :     }
     530                 : 
     531               0 :     mDocWriteSpeculativeTreeBuilder->Flush();
     532               0 :     mDocWriteSpeculativeTreeBuilder->DropHandles();
     533               0 :     mExecutor->FlushSpeculativeLoads();
     534                 :   }
     535                 : 
     536               0 :   return NS_OK;
     537                 : }
     538                 : 
     539                 : NS_IMETHODIMP
     540               0 : nsHtml5Parser::Terminate()
     541                 : {
     542                 :   // We should only call DidBuildModel once, so don't do anything if this is
     543                 :   // the second time that Terminate has been called.
     544               0 :   if (mExecutor->IsComplete()) {
     545               0 :     return NS_OK;
     546                 :   }
     547                 :   // XXX - [ until we figure out a way to break parser-sink circularity ]
     548                 :   // Hack - Hold a reference until we are completely done...
     549               0 :   nsCOMPtr<nsIParser> kungFuDeathGrip(this);
     550               0 :   nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip(mStreamParser);
     551               0 :   nsRefPtr<nsHtml5TreeOpExecutor> treeOpKungFuDeathGrip(mExecutor);
     552               0 :   if (mStreamParser) {
     553               0 :     mStreamParser->Terminate();
     554                 :   }
     555               0 :   return mExecutor->DidBuildModel(true);
     556                 : }
     557                 : 
     558                 : NS_IMETHODIMP
     559               0 : nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
     560                 :                              nsTArray<nsString>& aTagStack)
     561                 : {
     562               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     563                 : }
     564                 : 
     565                 : NS_IMETHODIMP
     566               0 : nsHtml5Parser::BuildModel()
     567                 : {
     568               0 :   NS_NOTREACHED("Don't call this!");
     569               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     570                 : }
     571                 : 
     572                 : NS_IMETHODIMP
     573               0 : nsHtml5Parser::CancelParsingEvents()
     574                 : {
     575               0 :   NS_NOTREACHED("Don't call this!");
     576               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     577                 : }
     578                 : 
     579                 : void
     580               0 : nsHtml5Parser::Reset()
     581                 : {
     582               0 :   NS_NOTREACHED("Don't call this!");
     583               0 : }
     584                 : 
     585                 : bool
     586               0 : nsHtml5Parser::CanInterrupt()
     587                 : {
     588                 :   // nsContentSink needs this to let nsContentSink::DidProcessATokenImpl
     589                 :   // interrupt.
     590               0 :   return true;
     591                 : }
     592                 : 
     593                 : bool
     594               0 : nsHtml5Parser::IsInsertionPointDefined()
     595                 : {
     596               0 :   return !mExecutor->IsFlushing() &&
     597               0 :     (!mStreamParser || mParserInsertedScriptsBeingEvaluated);
     598                 : }
     599                 : 
     600                 : void
     601               0 : nsHtml5Parser::BeginEvaluatingParserInsertedScript()
     602                 : {
     603               0 :   ++mParserInsertedScriptsBeingEvaluated;
     604               0 : }
     605                 : 
     606                 : void
     607               0 : nsHtml5Parser::EndEvaluatingParserInsertedScript()
     608                 : {
     609               0 :   --mParserInsertedScriptsBeingEvaluated;
     610               0 : }
     611                 : 
     612                 : void
     613               0 : nsHtml5Parser::MarkAsNotScriptCreated(const char* aCommand)
     614                 : {
     615               0 :   NS_PRECONDITION(!mStreamParser, "Must not call this twice.");
     616               0 :   eParserMode mode = NORMAL;
     617               0 :   if (!nsCRT::strcmp(aCommand, "view-source")) {
     618               0 :     mode = VIEW_SOURCE_HTML;
     619               0 :   } else if (!nsCRT::strcmp(aCommand, "view-source-xml")) {
     620               0 :     mode = VIEW_SOURCE_XML;
     621               0 :   } else if (!nsCRT::strcmp(aCommand, "view-source-plain")) {
     622               0 :     mode = VIEW_SOURCE_PLAIN;
     623               0 :   } else if (!nsCRT::strcmp(aCommand, "plain-text")) {
     624               0 :     mode = PLAIN_TEXT;
     625               0 :   } else if (!nsCRT::strcmp(aCommand, kLoadAsData)) {
     626               0 :     mode = LOAD_AS_DATA;
     627                 :   }
     628                 : #ifdef DEBUG
     629                 :   else {
     630               0 :     NS_ASSERTION(!nsCRT::strcmp(aCommand, "view") ||
     631                 :                  !nsCRT::strcmp(aCommand, "external-resource"),
     632                 :                  "Unsupported parser command!");
     633                 :   }
     634                 : #endif
     635               0 :   mStreamParser = new nsHtml5StreamParser(mExecutor, this, mode);
     636               0 : }
     637                 : 
     638                 : bool
     639               0 : nsHtml5Parser::IsScriptCreated()
     640                 : {
     641               0 :   return !mStreamParser;
     642                 : }
     643                 : 
     644                 : /* End nsIParser  */
     645                 : 
     646                 : // not from interface
     647                 : void
     648               0 : nsHtml5Parser::ParseUntilBlocked()
     649                 : {
     650               0 :   if (mBlocked || mExecutor->IsComplete() || mExecutor->IsBroken()) {
     651               0 :     return;
     652                 :   }
     653               0 :   NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle.");
     654               0 :   NS_ASSERTION(!mInDocumentWrite,
     655                 :     "ParseUntilBlocked entered while in doc.write!");
     656                 : 
     657               0 :   mDocWriteSpeculatorActive = false;
     658                 : 
     659               0 :   for (;;) {
     660               0 :     if (!mFirstBuffer->hasMore()) {
     661               0 :       if (mFirstBuffer == mLastBuffer) {
     662               0 :         if (mExecutor->IsComplete()) {
     663                 :           // something like cache manisfests stopped the parse in mid-flight
     664               0 :           return;
     665                 :         }
     666               0 :         if (mDocumentClosed) {
     667               0 :           NS_ASSERTION(!mStreamParser,
     668                 :                        "This should only happen with script-created parser.");
     669               0 :           mTokenizer->eof();
     670               0 :           mTreeBuilder->StreamEnded();
     671               0 :           mTreeBuilder->Flush();
     672               0 :           mExecutor->FlushDocumentWrite();
     673               0 :           mTokenizer->end();
     674               0 :           return;            
     675                 :         }
     676                 :         // never release the last buffer.
     677               0 :         NS_ASSERTION(!mLastBuffer->getStart() && !mLastBuffer->getEnd(),
     678                 :                      "Sentinel buffer had its indeces changed.");
     679               0 :         if (mStreamParser) {
     680               0 :           if (mReturnToStreamParserPermitted &&
     681               0 :               !mExecutor->IsScriptExecuting()) {
     682               0 :             mTreeBuilder->Flush();
     683               0 :             mReturnToStreamParserPermitted = false;
     684                 :             mStreamParser->ContinueAfterScripts(mTokenizer,
     685                 :                                                 mTreeBuilder,
     686               0 :                                                 mLastWasCR);
     687                 :           }
     688                 :         } else {
     689                 :           // Script-created parser
     690               0 :           mTreeBuilder->Flush();
     691                 :           // No need to flush the executor, because the executor is already
     692                 :           // in a flush
     693               0 :           NS_ASSERTION(mExecutor->IsInFlushLoop(),
     694                 :               "How did we come here without being in the flush loop?");
     695                 :         }
     696               0 :         return; // no more data for now but expecting more
     697                 :       }
     698               0 :       mFirstBuffer = mFirstBuffer->next;
     699               0 :       continue;
     700                 :     }
     701                 : 
     702               0 :     if (mBlocked || mExecutor->IsComplete()) {
     703               0 :       return;
     704                 :     }
     705                 : 
     706                 :     // now we have a non-empty buffer
     707               0 :     mFirstBuffer->adjust(mLastWasCR);
     708               0 :     mLastWasCR = false;
     709               0 :     if (mFirstBuffer->hasMore()) {
     710               0 :       bool inRootContext = (!mStreamParser && !mFirstBuffer->key);
     711               0 :       if (inRootContext) {
     712               0 :         mTokenizer->setLineNumber(mRootContextLineNumber);
     713                 :       }
     714               0 :       mLastWasCR = mTokenizer->tokenizeBuffer(mFirstBuffer);
     715               0 :       if (inRootContext) {
     716               0 :         mRootContextLineNumber = mTokenizer->getLineNumber();
     717                 :       }
     718               0 :       if (mTreeBuilder->HasScript()) {
     719               0 :         mTreeBuilder->Flush();
     720               0 :         mExecutor->FlushDocumentWrite();
     721                 :       }
     722               0 :       if (mBlocked) {
     723               0 :         return;
     724                 :       }
     725                 :     }
     726               0 :     continue;
     727                 :   }
     728                 : }
     729                 : 
     730                 : nsresult
     731               0 : nsHtml5Parser::Initialize(nsIDocument* aDoc,
     732                 :                           nsIURI* aURI,
     733                 :                           nsISupports* aContainer,
     734                 :                           nsIChannel* aChannel)
     735                 : {
     736               0 :   return mExecutor->Init(aDoc, aURI, aContainer, aChannel);
     737                 : }
     738                 : 
     739                 : void
     740               0 : nsHtml5Parser::StartTokenizer(bool aScriptingEnabled) {
     741               0 :   if (!aScriptingEnabled) {
     742               0 :     mExecutor->PreventScriptExecution();
     743                 :   }
     744               0 :   mTreeBuilder->setScriptingEnabled(aScriptingEnabled);
     745               0 :   mTokenizer->start();
     746               0 : }
     747                 : 
     748                 : void
     749               0 : nsHtml5Parser::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState,
     750                 :                                              PRInt32 aLine)
     751                 : {
     752               0 :   mTokenizer->resetToDataState();
     753               0 :   mTokenizer->setLineNumber(aLine);
     754               0 :   mTreeBuilder->loadState(aState, &mAtomTable);
     755               0 :   mLastWasCR = false;
     756               0 :   mReturnToStreamParserPermitted = true;
     757               0 : }
     758                 : 
     759                 : void
     760               0 : nsHtml5Parser::ContinueAfterFailedCharsetSwitch()
     761                 : {
     762               0 :   NS_PRECONDITION(mStreamParser, 
     763                 :     "Tried to continue after failed charset switch without a stream parser");
     764               0 :   mStreamParser->ContinueAfterFailedCharsetSwitch();
     765            4392 : }

Generated by: LCOV version 1.7