LCOV - code coverage report
Current view: directory - content/base/src - nsContentSink.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 649 197 30.4 %
Date: 2012-06-02 Functions: 45 28 62.2 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=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                 :  *   Henri Sivonen <hsivonen@iki.fi>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /*
      41                 :  * Base class for the XML and HTML content sinks, which construct a
      42                 :  * DOM based on information from the parser.
      43                 :  */
      44                 : 
      45                 : #include "nsContentSink.h"
      46                 : #include "nsScriptLoader.h"
      47                 : #include "nsIDocument.h"
      48                 : #include "nsIDOMDocument.h"
      49                 : #include "mozilla/css/Loader.h"
      50                 : #include "nsStyleConsts.h"
      51                 : #include "nsStyleLinkElement.h"
      52                 : #include "nsINodeInfo.h"
      53                 : #include "nsIDocShell.h"
      54                 : #include "nsIDocShellTreeItem.h"
      55                 : #include "nsCPrefetchService.h"
      56                 : #include "nsIURI.h"
      57                 : #include "nsNetUtil.h"
      58                 : #include "nsIHttpChannel.h"
      59                 : #include "nsIContent.h"
      60                 : #include "nsIScriptElement.h"
      61                 : #include "nsIParser.h"
      62                 : #include "nsContentErrors.h"
      63                 : #include "nsIPresShell.h"
      64                 : #include "nsPresContext.h"
      65                 : #include "nsIViewManager.h"
      66                 : #include "nsIContentViewer.h"
      67                 : #include "nsIAtom.h"
      68                 : #include "nsGkAtoms.h"
      69                 : #include "nsIDOMWindow.h"
      70                 : #include "nsIPrincipal.h"
      71                 : #include "nsIScriptGlobalObject.h"
      72                 : #include "nsNetCID.h"
      73                 : #include "nsIOfflineCacheUpdate.h"
      74                 : #include "nsIApplicationCache.h"
      75                 : #include "nsIApplicationCacheContainer.h"
      76                 : #include "nsIApplicationCacheChannel.h"
      77                 : #include "nsIScriptSecurityManager.h"
      78                 : #include "nsIDOMLoadStatus.h"
      79                 : #include "nsICookieService.h"
      80                 : #include "nsIPrompt.h"
      81                 : #include "nsServiceManagerUtils.h"
      82                 : #include "nsContentUtils.h"
      83                 : #include "nsCRT.h"
      84                 : #include "nsEscape.h"
      85                 : #include "nsWeakReference.h"
      86                 : #include "nsUnicharUtils.h"
      87                 : #include "nsNodeInfoManager.h"
      88                 : #include "nsIAppShell.h"
      89                 : #include "nsIWidget.h"
      90                 : #include "nsWidgetsCID.h"
      91                 : #include "nsIRequest.h"
      92                 : #include "nsNodeUtils.h"
      93                 : #include "nsIDOMNode.h"
      94                 : #include "nsThreadUtils.h"
      95                 : #include "nsPIDOMWindow.h"
      96                 : #include "mozAutoDocUpdate.h"
      97                 : #include "nsIWebNavigation.h"
      98                 : #include "nsIDocumentLoader.h"
      99                 : #include "nsICachingChannel.h"
     100                 : #include "nsICacheEntryDescriptor.h"
     101                 : #include "nsGenericHTMLElement.h"
     102                 : #include "nsHTMLDNSPrefetch.h"
     103                 : #include "nsISupportsPrimitives.h"
     104                 : #include "mozilla/Preferences.h"
     105                 : #include "nsParserConstants.h"
     106                 : 
     107                 : using namespace mozilla;
     108                 : 
     109                 : PRLogModuleInfo* gContentSinkLogModuleInfo;
     110                 : 
     111           29670 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
     112           29670 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
     113                 : 
     114           12183 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
     115           12142 :   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
     116           12142 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     117           11104 :   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
     118            2078 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     119            2078 :   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
     120            2078 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
     121            2078 : NS_INTERFACE_MAP_END
     122                 : 
     123            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
     124               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
     125               0 :   if (tmp->mDocument) {
     126               0 :     tmp->mDocument->RemoveObserver(tmp);
     127                 :   }
     128               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
     129               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParser)
     130               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNodeInfoManager)
     131               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptLoader)
     132               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     133               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
     134               2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
     135               2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
     136               2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
     137                 :                                                   nsNodeInfoManager)
     138               2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
     139               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     140                 : 
     141                 : 
     142            1051 : nsContentSink::nsContentSink()
     143                 : {
     144                 :   // We have a zeroing operator new
     145            1051 :   NS_ASSERTION(!mLayoutStarted, "What?");
     146            1051 :   NS_ASSERTION(!mDynamicLowerValue, "What?");
     147            1051 :   NS_ASSERTION(!mParsing, "What?");
     148            1051 :   NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
     149            1051 :   NS_ASSERTION(mDeflectedCount == 0, "What?");
     150            1051 :   NS_ASSERTION(!mDroppedTimer, "What?");
     151            1051 :   NS_ASSERTION(mInMonolithicContainer == 0, "What?");
     152            1051 :   NS_ASSERTION(mInNotification == 0, "What?");
     153            1051 :   NS_ASSERTION(!mDeferredLayoutStart, "What?");
     154                 : 
     155                 : #ifdef NS_DEBUG
     156            1051 :   if (!gContentSinkLogModuleInfo) {
     157             249 :     gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink");
     158                 :   }
     159                 : #endif
     160            1051 : }
     161                 : 
     162            2102 : nsContentSink::~nsContentSink()
     163                 : {
     164            1051 :   if (mDocument) {
     165                 :     // Remove ourselves just to be safe, though we really should have
     166                 :     // been removed in DidBuildModel if everything worked right.
     167            1038 :     mDocument->RemoveObserver(this);
     168                 :   }
     169            2102 : }
     170                 : 
     171                 : bool    nsContentSink::sNotifyOnTimer;
     172                 : PRInt32 nsContentSink::sBackoffCount;
     173                 : PRInt32 nsContentSink::sNotificationInterval;
     174                 : PRInt32 nsContentSink::sInteractiveDeflectCount;
     175                 : PRInt32 nsContentSink::sPerfDeflectCount;
     176                 : PRInt32 nsContentSink::sPendingEventMode;
     177                 : PRInt32 nsContentSink::sEventProbeRate;
     178                 : PRInt32 nsContentSink::sInteractiveParseTime;
     179                 : PRInt32 nsContentSink::sPerfParseTime;
     180                 : PRInt32 nsContentSink::sInteractiveTime;
     181                 : PRInt32 nsContentSink::sInitialPerfTime;
     182                 : PRInt32 nsContentSink::sEnablePerfMode;
     183                 : 
     184                 : void
     185            1404 : nsContentSink::InitializeStatics()
     186                 : {
     187                 :   Preferences::AddBoolVarCache(&sNotifyOnTimer,
     188            1404 :                                "content.notify.ontimer", true);
     189                 :   // -1 means never.
     190                 :   Preferences::AddIntVarCache(&sBackoffCount,
     191            1404 :                               "content.notify.backoffcount", -1);
     192                 :   // The gNotificationInterval has a dramatic effect on how long it
     193                 :   // takes to initially display content for slow connections.
     194                 :   // The current value provides good
     195                 :   // incremental display of content without causing an increase
     196                 :   // in page load time. If this value is set below 1/10 of second
     197                 :   // it starts to impact page load performance.
     198                 :   // see bugzilla bug 72138 for more info.
     199                 :   Preferences::AddIntVarCache(&sNotificationInterval,
     200            1404 :                               "content.notify.interval", 120000);
     201                 :   Preferences::AddIntVarCache(&sInteractiveDeflectCount,
     202            1404 :                               "content.sink.interactive_deflect_count", 0);
     203                 :   Preferences::AddIntVarCache(&sPerfDeflectCount,
     204            1404 :                               "content.sink.perf_deflect_count", 200);
     205                 :   Preferences::AddIntVarCache(&sPendingEventMode,
     206            1404 :                               "content.sink.pending_event_mode", 1);
     207                 :   Preferences::AddIntVarCache(&sEventProbeRate,
     208            1404 :                               "content.sink.event_probe_rate", 1);
     209                 :   Preferences::AddIntVarCache(&sInteractiveParseTime,
     210            1404 :                               "content.sink.interactive_parse_time", 3000);
     211                 :   Preferences::AddIntVarCache(&sPerfParseTime,
     212            1404 :                               "content.sink.perf_parse_time", 360000);
     213                 :   Preferences::AddIntVarCache(&sInteractiveTime,
     214            1404 :                               "content.sink.interactive_time", 750000);
     215                 :   Preferences::AddIntVarCache(&sInitialPerfTime,
     216            1404 :                               "content.sink.initial_perf_time", 2000000);
     217                 :   Preferences::AddIntVarCache(&sEnablePerfMode,
     218            1404 :                               "content.sink.enable_perf_mode", 0);
     219            1404 : }
     220                 : 
     221                 : nsresult
     222            1272 : nsContentSink::Init(nsIDocument* aDoc,
     223                 :                     nsIURI* aURI,
     224                 :                     nsISupports* aContainer,
     225                 :                     nsIChannel* aChannel)
     226                 : {
     227            1272 :   NS_PRECONDITION(aDoc, "null ptr");
     228            1272 :   NS_PRECONDITION(aURI, "null ptr");
     229                 : 
     230            1272 :   if (!aDoc || !aURI) {
     231               0 :     return NS_ERROR_NULL_POINTER;
     232                 :   }
     233                 : 
     234            1272 :   mDocument = aDoc;
     235                 : 
     236            1272 :   mDocumentURI = aURI;
     237            1272 :   mDocShell = do_QueryInterface(aContainer);
     238            1272 :   mScriptLoader = mDocument->ScriptLoader();
     239                 : 
     240            1272 :   if (!mRunsToCompletion) {
     241            1038 :     if (mDocShell) {
     242               0 :       PRUint32 loadType = 0;
     243               0 :       mDocShell->GetLoadType(&loadType);
     244               0 :       mDocument->SetChangeScrollPosWhenScrollingToRef(
     245               0 :         (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
     246                 :     }
     247                 : 
     248            1038 :     ProcessHTTPHeaders(aChannel);
     249                 :   }
     250                 : 
     251            1272 :   mCSSLoader = aDoc->CSSLoader();
     252                 : 
     253            1272 :   mNodeInfoManager = aDoc->NodeInfoManager();
     254                 : 
     255            1272 :   mBackoffCount = sBackoffCount;
     256                 : 
     257            1272 :   if (sEnablePerfMode != 0) {
     258               0 :     mDynamicLowerValue = sEnablePerfMode == 1;
     259               0 :     FavorPerformanceHint(!mDynamicLowerValue, 0);
     260                 :   }
     261                 : 
     262            1272 :   return NS_OK;
     263                 : }
     264                 : 
     265                 : NS_IMETHODIMP
     266               0 : nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
     267                 :                                 bool aWasAlternate,
     268                 :                                 nsresult aStatus)
     269                 : {
     270               0 :   NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
     271               0 :   if (!aWasAlternate) {
     272               0 :     NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
     273               0 :     --mPendingSheetCount;
     274                 : 
     275               0 :     if (mPendingSheetCount == 0 &&
     276                 :         (mDeferredLayoutStart || mDeferredFlushTags)) {
     277               0 :       if (mDeferredFlushTags) {
     278               0 :         FlushTags();
     279                 :       }
     280               0 :       if (mDeferredLayoutStart) {
     281                 :         // We might not have really started layout, since this sheet was still
     282                 :         // loading.  Do it now.  Probably doesn't matter whether we do this
     283                 :         // before or after we unblock scripts, but before feels saner.  Note
     284                 :         // that if mDeferredLayoutStart is true, that means any subclass
     285                 :         // StartLayout() stuff that needs to happen has already happened, so we
     286                 :         // don't need to worry about it.
     287               0 :         StartLayout(false);
     288                 :       }
     289                 : 
     290                 :       // Go ahead and try to scroll to our ref if we have one
     291               0 :       ScrollToRef();
     292                 :     }
     293                 :     
     294               0 :     mScriptLoader->RemoveExecuteBlocker();
     295                 :   }
     296                 : 
     297               0 :   return NS_OK;
     298                 : }
     299                 : 
     300                 : nsresult
     301            1038 : nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
     302                 : {
     303            2076 :   nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
     304                 :   
     305            1038 :   if (!httpchannel) {
     306             571 :     return NS_OK;
     307                 :   }
     308                 : 
     309                 :   // Note that the only header we care about is the "link" header, since we
     310                 :   // have all the infrastructure for kicking off stylesheet loads.
     311                 :   
     312             934 :   nsCAutoString linkHeader;
     313                 :   
     314             934 :   nsresult rv = httpchannel->GetResponseHeader(NS_LITERAL_CSTRING("link"),
     315             467 :                                                linkHeader);
     316             467 :   if (NS_SUCCEEDED(rv) && !linkHeader.IsEmpty()) {
     317               0 :     mDocument->SetHeaderData(nsGkAtoms::link,
     318               0 :                              NS_ConvertASCIItoUTF16(linkHeader));
     319                 : 
     320               0 :     NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
     321                 :                  "Already dispatched an event?");
     322                 : 
     323                 :     mProcessLinkHeaderEvent =
     324                 :       NS_NewNonOwningRunnableMethod(this,
     325               0 :         &nsContentSink::DoProcessLinkHeader);
     326               0 :     rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get());
     327               0 :     if (NS_FAILED(rv)) {
     328               0 :       mProcessLinkHeaderEvent.Forget();
     329                 :     }
     330                 :   }
     331                 :   
     332             467 :   return NS_OK;
     333                 : }
     334                 : 
     335                 : nsresult
     336               0 : nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
     337                 :                                  nsIContent* aContent)
     338                 : {
     339               0 :   nsresult rv = NS_OK;
     340                 :   // necko doesn't process headers coming in from the parser
     341                 : 
     342               0 :   mDocument->SetHeaderData(aHeader, aValue);
     343                 : 
     344               0 :   if (aHeader == nsGkAtoms::setcookie) {
     345                 :     // Note: Necko already handles cookies set via the channel.  We can't just
     346                 :     // call SetCookie on the channel because we want to do some security checks
     347                 :     // here and want to use the prompt associated to our current window, not
     348                 :     // the window where the channel was dispatched.
     349                 :     nsCOMPtr<nsICookieService> cookieServ =
     350               0 :       do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv);
     351               0 :     if (NS_FAILED(rv)) {
     352               0 :       return rv;
     353                 :     }
     354                 : 
     355                 :     // Get a URI from the document principal
     356                 : 
     357                 :     // We use the original codebase in case the codebase was changed
     358                 :     // by SetDomain
     359                 : 
     360                 :     // Note that a non-codebase principal (eg the system principal) will return
     361                 :     // a null URI.
     362               0 :     nsCOMPtr<nsIURI> codebaseURI;
     363               0 :     rv = mDocument->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
     364               0 :     NS_ENSURE_TRUE(codebaseURI, rv);
     365                 : 
     366               0 :     nsCOMPtr<nsIPrompt> prompt;
     367               0 :     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mDocument->GetScriptGlobalObject());
     368               0 :     if (window) {
     369               0 :       window->GetPrompter(getter_AddRefs(prompt));
     370                 :     }
     371                 : 
     372               0 :     nsCOMPtr<nsIChannel> channel;
     373               0 :     if (mParser) {
     374               0 :       mParser->GetChannel(getter_AddRefs(channel));
     375                 :     }
     376                 : 
     377               0 :     rv = cookieServ->SetCookieString(codebaseURI,
     378                 :                                      prompt,
     379               0 :                                      NS_ConvertUTF16toUTF8(aValue).get(),
     380               0 :                                      channel);
     381               0 :     if (NS_FAILED(rv)) {
     382               0 :       return rv;
     383                 :     }
     384                 :   }
     385               0 :   else if (aHeader == nsGkAtoms::msthemecompatible) {
     386                 :     // Disable theming for the presshell if the value is no.
     387                 :     // XXXbz don't we want to support this as an HTTP header too?
     388               0 :     nsAutoString value(aValue);
     389               0 :     if (value.LowerCaseEqualsLiteral("no")) {
     390               0 :       nsIPresShell* shell = mDocument->GetShell();
     391               0 :       if (shell) {
     392               0 :         shell->DisableThemeSupport();
     393                 :       }
     394                 :     }
     395                 :   }
     396                 : 
     397               0 :   return rv;
     398                 : }
     399                 : 
     400                 : 
     401                 : void
     402               0 : nsContentSink::DoProcessLinkHeader()
     403                 : {
     404               0 :   nsAutoString value;
     405               0 :   mDocument->GetHeaderData(nsGkAtoms::link, value);
     406               0 :   ProcessLinkHeader(nsnull, value);
     407               0 : }
     408                 : 
     409                 : // check whether the Link header field applies to the context resource
     410                 : // see <http://tools.ietf.org/html/rfc5988#section-5.2>
     411                 : 
     412                 : bool
     413               0 : nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
     414                 : {
     415               0 :   if (aAnchor.IsEmpty()) {
     416                 :     // anchor parameter not present or empty -> same document reference
     417               0 :     return true;
     418                 :   }
     419                 : 
     420               0 :   nsIURI* docUri = mDocument->GetDocumentURI();
     421                 : 
     422                 :   // the document URI might contain a fragment identifier ("#...')
     423                 :   // we want to ignore that because it's invisible to the server
     424                 :   // and just affects the local interpretation in the recipient
     425               0 :   nsCOMPtr<nsIURI> contextUri;
     426               0 :   nsresult rv = docUri->CloneIgnoringRef(getter_AddRefs(contextUri));
     427                 :   
     428               0 :   if (NS_FAILED(rv)) {
     429                 :     // copying failed
     430               0 :     return false;
     431                 :   }
     432                 :   
     433                 :   // resolve anchor against context    
     434               0 :   nsCOMPtr<nsIURI> resolvedUri;
     435               0 :   rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor,
     436               0 :       nsnull, contextUri);
     437                 :   
     438               0 :   if (NS_FAILED(rv)) {
     439                 :     // resolving failed
     440               0 :     return false;
     441                 :   }
     442                 : 
     443                 :   bool same;
     444               0 :   rv = contextUri->Equals(resolvedUri, &same); 
     445               0 :   if (NS_FAILED(rv)) {
     446                 :     // comparison failed
     447               0 :     return false;
     448                 :   }
     449                 : 
     450               0 :   return same;
     451                 : }
     452                 : 
     453                 : nsresult
     454               0 : nsContentSink::ProcessLinkHeader(nsIContent* aElement,
     455                 :                                  const nsAString& aLinkData)
     456                 : {
     457               0 :   nsresult rv = NS_OK;
     458                 : 
     459                 :   // keep track where we are within the header field
     460               0 :   bool seenParameters = false;
     461                 : 
     462                 :   // parse link content and call process style link
     463               0 :   nsAutoString href;
     464               0 :   nsAutoString rel;
     465               0 :   nsAutoString title;
     466               0 :   nsAutoString type;
     467               0 :   nsAutoString media;
     468               0 :   nsAutoString anchor;
     469                 : 
     470                 :   // copy to work buffer
     471               0 :   nsAutoString stringList(aLinkData);
     472                 : 
     473                 :   // put an extra null at the end
     474               0 :   stringList.Append(kNullCh);
     475                 : 
     476               0 :   PRUnichar* start = stringList.BeginWriting();
     477               0 :   PRUnichar* end   = start;
     478               0 :   PRUnichar* last  = start;
     479                 :   PRUnichar  endCh;
     480                 : 
     481               0 :   while (*start != kNullCh) {
     482                 :     // skip leading space
     483               0 :     while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) {
     484               0 :       ++start;
     485                 :     }
     486                 : 
     487               0 :     end = start;
     488               0 :     last = end - 1;
     489                 : 
     490               0 :     bool needsUnescape = false;
     491                 :     
     492                 :     // look for semicolon or comma
     493               0 :     while (*end != kNullCh && *end != kSemicolon && *end != kComma) {
     494               0 :       PRUnichar ch = *end;
     495                 : 
     496               0 :       if (ch == kQuote || ch == kLessThan) {
     497                 :         // quoted string
     498                 : 
     499               0 :         PRUnichar quote = ch;
     500               0 :         if (quote == kLessThan) {
     501               0 :           quote = kGreaterThan;
     502                 :         }
     503                 :         
     504               0 :         needsUnescape = (ch == kQuote);
     505                 :         
     506               0 :         PRUnichar* closeQuote = (end + 1);
     507                 : 
     508                 :         // seek closing quote
     509               0 :         while (*closeQuote != kNullCh && quote != *closeQuote) {
     510                 :           // in quoted-string, "\" is an escape character
     511               0 :           if (needsUnescape && *closeQuote == kBackSlash && *(closeQuote + 1) != kNullCh) {
     512               0 :             ++closeQuote;
     513                 :           }
     514                 : 
     515               0 :           ++closeQuote;
     516                 :         }
     517                 : 
     518               0 :         if (quote == *closeQuote) {
     519                 :           // found closer
     520                 : 
     521                 :           // skip to close quote
     522               0 :           end = closeQuote;
     523                 : 
     524               0 :           last = end - 1;
     525                 : 
     526               0 :           ch = *(end + 1);
     527                 : 
     528               0 :           if (ch != kNullCh && ch != kSemicolon && ch != kComma) {
     529                 :             // end string here
     530               0 :             *(++end) = kNullCh;
     531                 : 
     532               0 :             ch = *(end + 1);
     533                 : 
     534                 :             // keep going until semi or comma
     535               0 :             while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
     536               0 :               ++end;
     537                 : 
     538               0 :               ch = *end;
     539                 :             }
     540                 :           }
     541                 :         }
     542                 :       }
     543                 : 
     544               0 :       ++end;
     545               0 :       ++last;
     546                 :     }
     547                 : 
     548               0 :     endCh = *end;
     549                 : 
     550                 :     // end string here
     551               0 :     *end = kNullCh;
     552                 : 
     553               0 :     if (start < end) {
     554               0 :       if ((*start == kLessThan) && (*last == kGreaterThan)) {
     555               0 :         *last = kNullCh;
     556                 : 
     557                 :         // first instance of <...> wins
     558                 :         // also, do not allow hrefs after the first param was seen
     559               0 :         if (href.IsEmpty() && !seenParameters) {
     560               0 :           href = (start + 1);
     561               0 :           href.StripWhitespace();
     562                 :         }
     563                 :       } else {
     564               0 :         PRUnichar* equals = start;
     565               0 :         seenParameters = true;
     566                 : 
     567               0 :         while ((*equals != kNullCh) && (*equals != kEqual)) {
     568               0 :           equals++;
     569                 :         }
     570                 : 
     571               0 :         if (*equals != kNullCh) {
     572               0 :           *equals = kNullCh;
     573               0 :           nsAutoString  attr(start);
     574               0 :           attr.StripWhitespace();
     575                 : 
     576               0 :           PRUnichar* value = ++equals;
     577               0 :           while (nsCRT::IsAsciiSpace(*value)) {
     578               0 :             value++;
     579                 :           }
     580                 : 
     581               0 :           if ((*value == kQuote) && (*value == *last)) {
     582               0 :             *last = kNullCh;
     583               0 :             value++;
     584                 :           }
     585                 : 
     586               0 :           if (needsUnescape) {
     587                 :             // unescape in-place
     588               0 :             PRUnichar* unescaped = value;
     589               0 :             PRUnichar *src = value;
     590                 :             
     591               0 :             while (*src != kNullCh) {
     592               0 :               if (*src == kBackSlash && *(src + 1) != kNullCh) {
     593               0 :                 src++;
     594                 :               }
     595               0 :               *unescaped++ = *src++;
     596                 :             }
     597                 : 
     598               0 :             *unescaped = kNullCh;
     599                 :           }
     600                 :           
     601               0 :           if (attr.LowerCaseEqualsLiteral("rel")) {
     602               0 :             if (rel.IsEmpty()) {
     603               0 :               rel = value;
     604               0 :               rel.CompressWhitespace();
     605                 :             }
     606               0 :           } else if (attr.LowerCaseEqualsLiteral("title")) {
     607               0 :             if (title.IsEmpty()) {
     608               0 :               title = value;
     609               0 :               title.CompressWhitespace();
     610                 :             }
     611               0 :           } else if (attr.LowerCaseEqualsLiteral("type")) {
     612               0 :             if (type.IsEmpty()) {
     613               0 :               type = value;
     614               0 :               type.StripWhitespace();
     615                 :             }
     616               0 :           } else if (attr.LowerCaseEqualsLiteral("media")) {
     617               0 :             if (media.IsEmpty()) {
     618               0 :               media = value;
     619                 : 
     620                 :               // The HTML5 spec is formulated in terms of the CSS3 spec,
     621                 :               // which specifies that media queries are case insensitive.
     622               0 :               nsContentUtils::ASCIIToLower(media);
     623                 :             }
     624               0 :           } else if (attr.LowerCaseEqualsLiteral("anchor")) {
     625               0 :             if (anchor.IsEmpty()) {
     626               0 :               anchor = value;
     627               0 :               anchor.StripWhitespace();
     628                 :             }
     629                 :           }
     630                 :         }
     631                 :       }
     632                 :     }
     633                 : 
     634               0 :     if (endCh == kComma) {
     635                 :       // hit a comma, process what we've got so far
     636                 : 
     637               0 :       href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
     638               0 :       if (!href.IsEmpty() && !rel.IsEmpty()) {
     639               0 :         rv = ProcessLink(aElement, anchor, href, rel, title, type, media);
     640                 :       }
     641                 : 
     642               0 :       href.Truncate();
     643               0 :       rel.Truncate();
     644               0 :       title.Truncate();
     645               0 :       type.Truncate();
     646               0 :       media.Truncate();
     647               0 :       anchor.Truncate();
     648                 :       
     649               0 :       seenParameters = false;
     650                 :     }
     651                 : 
     652               0 :     start = ++end;
     653                 :   }
     654                 :                 
     655               0 :   href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
     656               0 :   if (!href.IsEmpty() && !rel.IsEmpty()) {
     657               0 :     rv = ProcessLink(aElement, anchor, href, rel, title, type, media);
     658                 :   }
     659                 : 
     660               0 :   return rv;
     661                 : }
     662                 : 
     663                 : 
     664                 : nsresult
     665               0 : nsContentSink::ProcessLink(nsIContent* aElement,
     666                 :                            const nsSubstring& aAnchor, const nsSubstring& aHref,
     667                 :                            const nsSubstring& aRel, const nsSubstring& aTitle,
     668                 :                            const nsSubstring& aType, const nsSubstring& aMedia)
     669                 : {
     670               0 :   PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel);
     671                 : 
     672                 :   // The link relation may apply to a different resource, specified
     673                 :   // in the anchor parameter. For the link relations supported so far,
     674                 :   // we simply abort if the link applies to a resource different to the
     675                 :   // one we've loaded
     676               0 :   if (!LinkContextIsOurDocument(aAnchor)) {
     677               0 :     return NS_OK;
     678                 :   }
     679                 :   
     680               0 :   bool hasPrefetch = linkTypes & PREFETCH;
     681                 :   // prefetch href if relation is "next" or "prefetch"
     682               0 :   if (hasPrefetch || (linkTypes & NEXT)) {
     683               0 :     PrefetchHref(aHref, aElement, hasPrefetch);
     684                 :   }
     685                 : 
     686               0 :   if (!aHref.IsEmpty() && (linkTypes & DNS_PREFETCH)) {
     687               0 :     PrefetchDNS(aHref);
     688                 :   }
     689                 : 
     690                 :   // is it a stylesheet link?
     691               0 :   if (!(linkTypes & STYLESHEET)) {
     692               0 :     return NS_OK;
     693                 :   }
     694                 : 
     695               0 :   bool isAlternate = linkTypes & ALTERNATE;
     696                 :   return ProcessStyleLink(aElement, aHref, isAlternate, aTitle, aType,
     697               0 :                           aMedia);
     698                 : }
     699                 : 
     700                 : nsresult
     701               0 : nsContentSink::ProcessStyleLink(nsIContent* aElement,
     702                 :                                 const nsSubstring& aHref,
     703                 :                                 bool aAlternate,
     704                 :                                 const nsSubstring& aTitle,
     705                 :                                 const nsSubstring& aType,
     706                 :                                 const nsSubstring& aMedia)
     707                 : {
     708               0 :   if (aAlternate && aTitle.IsEmpty()) {
     709                 :     // alternates must have title return without error, for now
     710               0 :     return NS_OK;
     711                 :   }
     712                 : 
     713               0 :   nsAutoString  mimeType;
     714               0 :   nsAutoString  params;
     715               0 :   nsContentUtils::SplitMimeType(aType, mimeType, params);
     716                 : 
     717                 :   // see bug 18817
     718               0 :   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     719                 :     // Unknown stylesheet language
     720               0 :     return NS_OK;
     721                 :   }
     722                 : 
     723               0 :   nsCOMPtr<nsIURI> url;
     724               0 :   nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull,
     725               0 :                           mDocument->GetDocBaseURI());
     726                 :   
     727               0 :   if (NS_FAILED(rv)) {
     728                 :     // The URI is bad, move along, don't propagate the error (for now)
     729               0 :     return NS_OK;
     730                 :   }
     731                 : 
     732                 :   // If this is a fragment parser, we don't want to observe.
     733                 :   bool isAlternate;
     734                 :   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
     735               0 :                                  mRunsToCompletion ? nsnull : this, &isAlternate);
     736               0 :   NS_ENSURE_SUCCESS(rv, rv);
     737                 :   
     738               0 :   if (!isAlternate && !mRunsToCompletion) {
     739               0 :     ++mPendingSheetCount;
     740               0 :     mScriptLoader->AddExecuteBlocker();
     741                 :   }
     742                 : 
     743               0 :   return NS_OK;
     744                 : }
     745                 : 
     746                 : 
     747                 : nsresult
     748               0 : nsContentSink::ProcessMETATag(nsIContent* aContent)
     749                 : {
     750               0 :   NS_ASSERTION(aContent, "missing meta-element");
     751                 : 
     752               0 :   nsresult rv = NS_OK;
     753                 : 
     754                 :   // set any HTTP-EQUIV data into document's header data as well as url
     755               0 :   nsAutoString header;
     756               0 :   aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     757               0 :   if (!header.IsEmpty()) {
     758               0 :     nsAutoString result;
     759               0 :     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
     760               0 :     if (!result.IsEmpty()) {
     761               0 :       nsContentUtils::ASCIIToLower(header);
     762               0 :       nsCOMPtr<nsIAtom> fieldAtom(do_GetAtom(header));
     763               0 :       rv = ProcessHeaderData(fieldAtom, result, aContent); 
     764                 :     }
     765                 :   }
     766               0 :   NS_ENSURE_SUCCESS(rv, rv);
     767                 : 
     768               0 :   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
     769               0 :                             nsGkAtoms::handheldFriendly, eIgnoreCase)) {
     770               0 :     nsAutoString result;
     771               0 :     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
     772               0 :     if (!result.IsEmpty()) {
     773               0 :       nsContentUtils::ASCIIToLower(result);
     774               0 :       mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
     775                 :     }
     776                 :   }
     777                 : 
     778               0 :   return rv;
     779                 : }
     780                 : 
     781                 : 
     782                 : void
     783               0 : nsContentSink::PrefetchHref(const nsAString &aHref,
     784                 :                             nsIContent *aSource,
     785                 :                             bool aExplicit)
     786                 : {
     787                 :   //
     788                 :   // SECURITY CHECK: disable prefetching from mailnews!
     789                 :   //
     790                 :   // walk up the docshell tree to see if any containing
     791                 :   // docshell are of type MAIL.
     792                 :   //
     793               0 :   if (!mDocShell)
     794               0 :     return;
     795                 : 
     796               0 :   nsCOMPtr<nsIDocShell> docshell = mDocShell;
     797                 : 
     798               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem, parentItem;
     799               0 :   do {
     800               0 :     PRUint32 appType = 0;
     801               0 :     nsresult rv = docshell->GetAppType(&appType);
     802               0 :     if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
     803                 :       return; // do not prefetch from mailnews
     804               0 :     treeItem = do_QueryInterface(docshell);
     805               0 :     if (treeItem) {
     806               0 :       treeItem->GetParent(getter_AddRefs(parentItem));
     807               0 :       if (parentItem) {
     808               0 :         treeItem = parentItem;
     809               0 :         docshell = do_QueryInterface(treeItem);
     810               0 :         if (!docshell) {
     811               0 :           NS_ERROR("cannot get a docshell from a treeItem!");
     812                 :           return;
     813                 :         }
     814                 :       }
     815                 :     }
     816               0 :   } while (parentItem);
     817                 :   
     818                 :   // OK, we passed the security check...
     819                 :   
     820               0 :   nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
     821               0 :   if (prefetchService) {
     822                 :     // construct URI using document charset
     823               0 :     const nsACString &charset = mDocument->GetDocumentCharacterSet();
     824               0 :     nsCOMPtr<nsIURI> uri;
     825               0 :     NS_NewURI(getter_AddRefs(uri), aHref,
     826               0 :               charset.IsEmpty() ? nsnull : PromiseFlatCString(charset).get(),
     827               0 :               mDocument->GetDocBaseURI());
     828               0 :     if (uri) {
     829               0 :       nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aSource);
     830               0 :       prefetchService->PrefetchURI(uri, mDocumentURI, domNode, aExplicit);
     831                 :     }
     832                 :   }
     833                 : }
     834                 : 
     835                 : void
     836               0 : nsContentSink::PrefetchDNS(const nsAString &aHref)
     837                 : {
     838               0 :   nsAutoString hostname;
     839                 : 
     840               0 :   if (StringBeginsWith(aHref, NS_LITERAL_STRING("//")))  {
     841               0 :     hostname = Substring(aHref, 2);
     842                 :   }
     843                 :   else {
     844               0 :     nsCOMPtr<nsIURI> uri;
     845               0 :     NS_NewURI(getter_AddRefs(uri), aHref);
     846               0 :     if (!uri) {
     847                 :       return;
     848                 :     }
     849               0 :     nsCAutoString host;
     850               0 :     uri->GetHost(host);
     851               0 :     CopyUTF8toUTF16(host, hostname);
     852                 :   }
     853                 : 
     854               0 :   if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
     855               0 :     nsHTMLDNSPrefetch::PrefetchLow(hostname);
     856                 :   }
     857                 : }
     858                 : 
     859                 : nsresult
     860               0 : nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
     861                 :                                  nsIURI *aManifestURI,
     862                 :                                  bool aFetchedWithHTTPGetOrEquiv,
     863                 :                                  CacheSelectionAction *aAction)
     864                 : {
     865                 :   nsresult rv;
     866                 : 
     867               0 :   *aAction = CACHE_SELECTION_NONE;
     868                 : 
     869                 :   nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
     870               0 :     do_QueryInterface(mDocument);
     871               0 :   NS_ASSERTION(applicationCacheDocument,
     872                 :                "mDocument must implement nsIApplicationCacheContainer.");
     873                 : 
     874               0 :   if (aLoadApplicationCache) {
     875               0 :     nsCAutoString groupID;
     876               0 :     rv = aLoadApplicationCache->GetGroupID(groupID);
     877               0 :     NS_ENSURE_SUCCESS(rv, rv);
     878                 : 
     879               0 :     nsCOMPtr<nsIURI> groupURI;
     880               0 :     rv = NS_NewURI(getter_AddRefs(groupURI), groupID);
     881               0 :     NS_ENSURE_SUCCESS(rv, rv);
     882                 : 
     883               0 :     bool equal = false;
     884               0 :     rv = groupURI->Equals(aManifestURI, &equal);
     885               0 :     NS_ENSURE_SUCCESS(rv, rv);
     886                 : 
     887               0 :     if (!equal) {
     888                 :       // This is a foreign entry, force a reload to avoid loading the foreign
     889                 :       // entry. The entry will be marked as foreign to avoid loading it again.
     890                 : 
     891               0 :       *aAction = CACHE_SELECTION_RELOAD;
     892                 :     }
     893                 :     else {
     894                 :       // The http manifest attribute URI is equal to the manifest URI of
     895                 :       // the cache the document was loaded from - associate the document with
     896                 :       // that cache and invoke the cache update process.
     897                 : #ifdef NS_DEBUG
     898               0 :       nsCAutoString docURISpec, clientID;
     899               0 :       mDocumentURI->GetAsciiSpec(docURISpec);
     900               0 :       aLoadApplicationCache->GetClientID(clientID);
     901               0 :       SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
     902                 :           ("Selection: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
     903                 : #endif
     904                 : 
     905               0 :       rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
     906               0 :       NS_ENSURE_SUCCESS(rv, rv);
     907                 : 
     908                 :       // Document will be added as implicit entry to the cache as part of
     909                 :       // the update process.
     910               0 :       *aAction = CACHE_SELECTION_UPDATE;
     911                 :     }
     912                 :   }
     913                 :   else {
     914                 :     // The document was not loaded from an application cache
     915                 :     // Here we know the manifest has the same origin as the
     916                 :     // document. There is call to CheckMayLoad() on it above.
     917                 : 
     918               0 :     if (!aFetchedWithHTTPGetOrEquiv) {
     919                 :       // The document was not loaded using HTTP GET or equivalent
     920                 :       // method. The spec says to run the cache selection algorithm w/o
     921                 :       // the manifest specified.
     922               0 :       *aAction = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
     923                 :     }
     924                 :     else {
     925                 :       // Always do an update in this case
     926               0 :       *aAction = CACHE_SELECTION_UPDATE;
     927                 :     }
     928                 :   }
     929                 : 
     930               0 :   return NS_OK;
     931                 : }
     932                 : 
     933                 : nsresult
     934               0 : nsContentSink::SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
     935                 :                                            nsIURI **aManifestURI,
     936                 :                                            CacheSelectionAction *aAction)
     937                 : {
     938               0 :   *aManifestURI = nsnull;
     939               0 :   *aAction = CACHE_SELECTION_NONE;
     940                 : 
     941                 :   nsresult rv;
     942                 : 
     943               0 :   if (aLoadApplicationCache) {
     944                 :     // The document was loaded from an application cache, use that
     945                 :     // application cache as the document's application cache.
     946                 :     nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
     947               0 :       do_QueryInterface(mDocument);
     948               0 :     NS_ASSERTION(applicationCacheDocument,
     949                 :                  "mDocument must implement nsIApplicationCacheContainer.");
     950                 : 
     951                 : #ifdef NS_DEBUG
     952               0 :     nsCAutoString docURISpec, clientID;
     953               0 :     mDocumentURI->GetAsciiSpec(docURISpec);
     954               0 :     aLoadApplicationCache->GetClientID(clientID);
     955               0 :     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
     956                 :         ("Selection, no manifest: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
     957                 : #endif
     958                 : 
     959               0 :     rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
     960               0 :     NS_ENSURE_SUCCESS(rv, rv);
     961                 : 
     962                 :     // Return the uri and invoke the update process for the selected
     963                 :     // application cache.
     964               0 :     nsCAutoString groupID;
     965               0 :     rv = aLoadApplicationCache->GetGroupID(groupID);
     966               0 :     NS_ENSURE_SUCCESS(rv, rv);
     967                 : 
     968               0 :     rv = NS_NewURI(aManifestURI, groupID);
     969               0 :     NS_ENSURE_SUCCESS(rv, rv);
     970                 : 
     971               0 :     *aAction = CACHE_SELECTION_UPDATE;
     972                 :   }
     973                 : 
     974               0 :   return NS_OK;
     975                 : }
     976                 : 
     977                 : void
     978               1 : nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
     979                 : {
     980                 :   // Only check the manifest for root document nodes.
     981               1 :   if (aElement != mDocument->GetRootElement()) {
     982               0 :     return;
     983                 :   }
     984                 : 
     985                 :   // Don't bother processing offline manifest for documents
     986                 :   // without a docshell
     987               1 :   if (!mDocShell) {
     988               1 :     return;
     989                 :   }
     990                 : 
     991                 :   // Check for a manifest= attribute.
     992               0 :   nsAutoString manifestSpec;
     993               0 :   aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
     994               0 :   ProcessOfflineManifest(manifestSpec);
     995                 : }
     996                 : 
     997                 : void
     998             234 : nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
     999                 : {
    1000                 :   // Don't bother processing offline manifest for documents
    1001                 :   // without a docshell
    1002             234 :   if (!mDocShell) {
    1003             234 :     return;
    1004                 :   }
    1005                 : 
    1006                 :   nsresult rv;
    1007                 : 
    1008                 :   // Grab the application cache the document was loaded from, if any.
    1009               0 :   nsCOMPtr<nsIApplicationCache> applicationCache;
    1010                 : 
    1011                 :   nsCOMPtr<nsIApplicationCacheChannel> applicationCacheChannel =
    1012               0 :     do_QueryInterface(mDocument->GetChannel());
    1013               0 :   if (applicationCacheChannel) {
    1014                 :     bool loadedFromApplicationCache;
    1015               0 :     rv = applicationCacheChannel->GetLoadedFromApplicationCache(
    1016               0 :       &loadedFromApplicationCache);
    1017               0 :     if (NS_FAILED(rv)) {
    1018                 :       return;
    1019                 :     }
    1020                 : 
    1021               0 :     if (loadedFromApplicationCache) {
    1022               0 :       rv = applicationCacheChannel->GetApplicationCache(
    1023               0 :         getter_AddRefs(applicationCache));
    1024               0 :       if (NS_FAILED(rv)) {
    1025                 :         return;
    1026                 :       }
    1027                 :     }
    1028                 :   }
    1029                 : 
    1030               0 :   if (aManifestSpec.IsEmpty() && !applicationCache) {
    1031                 :     // Not loaded from an application cache, and no manifest
    1032                 :     // attribute.  Nothing to do here.
    1033                 :     return;
    1034                 :   }
    1035                 : 
    1036               0 :   CacheSelectionAction action = CACHE_SELECTION_NONE;
    1037               0 :   nsCOMPtr<nsIURI> manifestURI;
    1038                 : 
    1039               0 :   if (aManifestSpec.IsEmpty()) {
    1040               0 :     action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
    1041                 :   }
    1042                 :   else {
    1043               0 :     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
    1044                 :                                               aManifestSpec, mDocument,
    1045               0 :                                               mDocumentURI);
    1046               0 :     if (!manifestURI) {
    1047                 :       return;
    1048                 :     }
    1049                 : 
    1050                 :     // Documents must list a manifest from the same origin
    1051               0 :     rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true);
    1052               0 :     if (NS_FAILED(rv)) {
    1053               0 :       action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
    1054                 :     }
    1055                 :     else {
    1056                 :       // Only continue if the document has permission to use offline APIs.
    1057               0 :       if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
    1058                 :         return;
    1059                 :       }
    1060                 : 
    1061               0 :       bool fetchedWithHTTPGetOrEquiv = false;
    1062               0 :       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mDocument->GetChannel()));
    1063               0 :       if (httpChannel) {
    1064               0 :         nsCAutoString method;
    1065               0 :         rv = httpChannel->GetRequestMethod(method);
    1066               0 :         if (NS_SUCCEEDED(rv))
    1067               0 :           fetchedWithHTTPGetOrEquiv = method.Equals("GET");
    1068                 :       }
    1069                 : 
    1070                 :       rv = SelectDocAppCache(applicationCache, manifestURI,
    1071               0 :                              fetchedWithHTTPGetOrEquiv, &action);
    1072               0 :       if (NS_FAILED(rv)) {
    1073                 :         return;
    1074                 :       }
    1075                 :     }
    1076                 :   }
    1077                 : 
    1078               0 :   if (action == CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST) {
    1079                 :     rv = SelectDocAppCacheNoManifest(applicationCache,
    1080               0 :                                      getter_AddRefs(manifestURI),
    1081               0 :                                      &action);
    1082               0 :     if (NS_FAILED(rv)) {
    1083                 :       return;
    1084                 :     }
    1085                 :   }
    1086                 : 
    1087               0 :   switch (action)
    1088                 :   {
    1089                 :   case CACHE_SELECTION_NONE:
    1090               0 :     break;
    1091                 :   case CACHE_SELECTION_UPDATE: {
    1092                 :     nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
    1093               0 :       do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
    1094                 : 
    1095               0 :     if (updateService) {
    1096               0 :       nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(mDocument);
    1097               0 :       updateService->ScheduleOnDocumentStop(manifestURI, mDocumentURI, domdoc);
    1098                 :     }
    1099                 :     break;
    1100                 :   }
    1101                 :   case CACHE_SELECTION_RELOAD: {
    1102                 :     // This situation occurs only for toplevel documents, see bottom
    1103                 :     // of SelectDocAppCache method.
    1104                 :     // The document has been loaded from a different offline cache group than
    1105                 :     // the manifest it refers to, i.e. this is a foreign entry, mark it as such 
    1106                 :     // and force a reload to avoid loading it.  The next attempt will not 
    1107                 :     // choose it.
    1108                 : 
    1109               0 :     applicationCacheChannel->MarkOfflineCacheEntryAsForeign();
    1110                 : 
    1111               0 :     nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
    1112                 : 
    1113               0 :     webNav->Stop(nsIWebNavigation::STOP_ALL);
    1114               0 :     webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
    1115                 :     break;
    1116                 :   }
    1117                 :   default:
    1118               0 :     NS_ASSERTION(false,
    1119                 :           "Cache selection algorithm didn't decide on proper action");
    1120               0 :     break;
    1121                 :   }
    1122                 : }
    1123                 : 
    1124                 : void
    1125            1038 : nsContentSink::ScrollToRef()
    1126                 : {
    1127            1038 :   mDocument->ScrollToRef();
    1128            1038 : }
    1129                 : 
    1130                 : void
    1131            2088 : nsContentSink::StartLayout(bool aIgnorePendingSheets)
    1132                 : {
    1133            2088 :   if (mLayoutStarted) {
    1134                 :     // Nothing to do here
    1135            1038 :     return;
    1136                 :   }
    1137                 :   
    1138            1050 :   mDeferredLayoutStart = true;
    1139                 : 
    1140            1050 :   if (!aIgnorePendingSheets && WaitForPendingSheets()) {
    1141                 :     // Bail out; we'll start layout when the sheets load
    1142               0 :     return;
    1143                 :   }
    1144                 : 
    1145            1050 :   mDeferredLayoutStart = false;
    1146                 : 
    1147                 :   // Notify on all our content.  If none of our presshells have started layout
    1148                 :   // yet it'll be a no-op except for updating our data structures, a la
    1149                 :   // UpdateChildCounts() (because we don't want to double-notify on whatever we
    1150                 :   // have right now).  If some of them _have_ started layout, we want to make
    1151                 :   // sure to flush tags instead of just calling UpdateChildCounts() after we
    1152                 :   // loop over the shells.
    1153            1050 :   FlushTags();
    1154                 : 
    1155            1050 :   mLayoutStarted = true;
    1156            1050 :   mLastNotificationTime = PR_Now();
    1157                 : 
    1158            1050 :   mDocument->SetMayStartLayout(true);
    1159            2100 :   nsCOMPtr<nsIPresShell> shell = mDocument->GetShell();
    1160                 :   // Make sure we don't call InitialReflow() for a shell that has
    1161                 :   // already called it. This can happen when the layout frame for
    1162                 :   // an iframe is constructed *between* the Embed() call for the
    1163                 :   // docshell in the iframe, and the content sink's call to OpenBody().
    1164                 :   // (Bug 153815)
    1165            1050 :   if (shell && !shell->DidInitialReflow()) {
    1166               0 :     nsRect r = shell->GetPresContext()->GetVisibleArea();
    1167               0 :     nsCOMPtr<nsIPresShell> shellGrip = shell;
    1168               0 :     nsresult rv = shell->InitialReflow(r.width, r.height);
    1169               0 :     if (NS_FAILED(rv)) {
    1170                 :       return;
    1171                 :     }
    1172                 :   }
    1173                 : 
    1174                 :   // If the document we are loading has a reference or it is a
    1175                 :   // frameset document, disable the scroll bars on the views.
    1176                 : 
    1177            1050 :   mDocument->SetScrollToRef(mDocumentURI);
    1178                 : }
    1179                 : 
    1180                 : void
    1181            1711 : nsContentSink::NotifyAppend(nsIContent* aContainer, PRUint32 aStartIndex)
    1182                 : {
    1183            1711 :   if (aContainer->GetCurrentDoc() != mDocument) {
    1184                 :     // aContainer is not actually in our document anymore.... Just bail out of
    1185                 :     // here; notifying on our document for this append would be wrong.
    1186               0 :     return;
    1187                 :   }
    1188                 : 
    1189            1711 :   mInNotification++;
    1190                 :   
    1191                 :   {
    1192                 :     // Scope so we call EndUpdate before we decrease mInNotification
    1193            3422 :     MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
    1194                 :     nsNodeUtils::ContentAppended(aContainer,
    1195            1711 :                                  aContainer->GetChildAt(aStartIndex),
    1196            3422 :                                  aStartIndex);
    1197            1711 :     mLastNotificationTime = PR_Now();
    1198                 :   }
    1199                 : 
    1200            1711 :   mInNotification--;
    1201                 : }
    1202                 : 
    1203                 : NS_IMETHODIMP
    1204               0 : nsContentSink::Notify(nsITimer *timer)
    1205                 : {
    1206               0 :   if (mParsing) {
    1207                 :     // We shouldn't interfere with our normal DidProcessAToken logic
    1208               0 :     mDroppedTimer = true;
    1209               0 :     return NS_OK;
    1210                 :   }
    1211                 :   
    1212                 : #ifdef MOZ_DEBUG
    1213                 :   {
    1214                 :     PRTime now = PR_Now();
    1215                 :     PRInt64 diff, interval;
    1216                 :     PRInt32 delay;
    1217                 : 
    1218                 :     LL_I2L(interval, GetNotificationInterval());
    1219                 :     LL_SUB(diff, now, mLastNotificationTime);
    1220                 : 
    1221                 :     LL_SUB(diff, diff, interval);
    1222                 :     LL_L2I(delay, diff);
    1223                 :     delay /= PR_USEC_PER_MSEC;
    1224                 : 
    1225                 :     mBackoffCount--;
    1226                 :     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1227                 :                ("nsContentSink::Notify: reflow on a timer: %d milliseconds "
    1228                 :                 "late, backoff count: %d", delay, mBackoffCount));
    1229                 :   }
    1230                 : #endif
    1231                 : 
    1232               0 :   if (WaitForPendingSheets()) {
    1233               0 :     mDeferredFlushTags = true;
    1234                 :   } else {
    1235               0 :     FlushTags();
    1236                 : 
    1237                 :     // Now try and scroll to the reference
    1238                 :     // XXX Should we scroll unconditionally for history loads??
    1239               0 :     ScrollToRef();
    1240                 :   }
    1241                 : 
    1242               0 :   mNotificationTimer = nsnull;
    1243               0 :   return NS_OK;
    1244                 : }
    1245                 : 
    1246                 : bool
    1247           75318 : nsContentSink::IsTimeToNotify()
    1248                 : {
    1249           75318 :   if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
    1250                 :       mInMonolithicContainer) {
    1251            1793 :     return false;
    1252                 :   }
    1253                 : 
    1254           73525 :   if (WaitForPendingSheets()) {
    1255               0 :     mDeferredFlushTags = true;
    1256               0 :     return false;
    1257                 :   }
    1258                 : 
    1259           73525 :   PRTime now = PR_Now();
    1260                 :   PRInt64 interval, diff;
    1261                 : 
    1262           73525 :   LL_I2L(interval, GetNotificationInterval());
    1263           73525 :   LL_SUB(diff, now, mLastNotificationTime);
    1264                 : 
    1265           73525 :   if (LL_CMP(diff, >, interval)) {
    1266               0 :     mBackoffCount--;
    1267               0 :     return true;
    1268                 :   }
    1269                 : 
    1270           73525 :   return false;
    1271                 : }
    1272                 : 
    1273                 : nsresult
    1274            1117 : nsContentSink::WillInterruptImpl()
    1275                 : {
    1276            1117 :   nsresult result = NS_OK;
    1277                 : 
    1278            1117 :   SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
    1279                 :              ("nsContentSink::WillInterrupt: this=%p", this));
    1280                 : #ifndef SINK_NO_INCREMENTAL
    1281            1117 :   if (WaitForPendingSheets()) {
    1282               0 :     mDeferredFlushTags = true;
    1283            1117 :   } else if (sNotifyOnTimer && mLayoutStarted) {
    1284            1114 :     if (mBackoffCount && !mInMonolithicContainer) {
    1285            1114 :       PRInt64 now = PR_Now();
    1286            1114 :       PRInt64 interval = GetNotificationInterval();
    1287            1114 :       PRInt64 diff = now - mLastNotificationTime;
    1288                 : 
    1289                 :       // If it's already time for us to have a notification
    1290            1114 :       if (diff > interval || mDroppedTimer) {
    1291               0 :         mBackoffCount--;
    1292               0 :         SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1293                 :                    ("nsContentSink::WillInterrupt: flushing tags since we've "
    1294                 :                     "run out time; backoff count: %d", mBackoffCount));
    1295               0 :         result = FlushTags();
    1296               0 :         if (mDroppedTimer) {
    1297               0 :           ScrollToRef();
    1298               0 :           mDroppedTimer = false;
    1299                 :         }
    1300            1114 :       } else if (!mNotificationTimer) {
    1301             976 :         interval -= diff;
    1302             976 :         PRInt32 delay = interval;
    1303                 : 
    1304                 :         // Convert to milliseconds
    1305             976 :         delay /= PR_USEC_PER_MSEC;
    1306                 : 
    1307                 :         mNotificationTimer = do_CreateInstance("@mozilla.org/timer;1",
    1308             976 :                                                &result);
    1309             976 :         if (NS_SUCCEEDED(result)) {
    1310             976 :           SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1311                 :                      ("nsContentSink::WillInterrupt: setting up timer with "
    1312                 :                       "delay %d", delay));
    1313                 : 
    1314                 :           result =
    1315             976 :             mNotificationTimer->InitWithCallback(this, delay,
    1316             976 :                                                  nsITimer::TYPE_ONE_SHOT);
    1317             976 :           if (NS_FAILED(result)) {
    1318               0 :             mNotificationTimer = nsnull;
    1319                 :           }
    1320                 :         }
    1321                 :       }
    1322            1114 :     }
    1323                 :   } else {
    1324               3 :     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1325                 :                ("nsContentSink::WillInterrupt: flushing tags "
    1326                 :                 "unconditionally"));
    1327               3 :     result = FlushTags();
    1328                 :   }
    1329                 : #endif
    1330                 : 
    1331            1117 :   mParsing = false;
    1332                 : 
    1333            1117 :   return result;
    1334                 : }
    1335                 : 
    1336                 : nsresult
    1337            2156 : nsContentSink::WillResumeImpl()
    1338                 : {
    1339            2156 :   SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
    1340                 :              ("nsContentSink::WillResume: this=%p", this));
    1341                 : 
    1342            2156 :   mParsing = true;
    1343                 : 
    1344            2156 :   return NS_OK;
    1345                 : }
    1346                 : 
    1347                 : nsresult
    1348          207594 : nsContentSink::DidProcessATokenImpl()
    1349                 : {
    1350          207594 :   if (mRunsToCompletion || !mParser) {
    1351               6 :     return NS_OK;
    1352                 :   }
    1353                 : 
    1354                 :   // Get the current user event time
    1355          207588 :   nsIPresShell *shell = mDocument->GetShell();
    1356          207588 :   if (!shell) {
    1357                 :     // If there's no pres shell in the document, return early since
    1358                 :     // we're not laying anything out here.
    1359          207588 :     return NS_OK;
    1360                 :   }
    1361                 : 
    1362                 :   // Increase before comparing to gEventProbeRate
    1363               0 :   ++mDeflectedCount;
    1364                 : 
    1365                 :   // Check if there's a pending event
    1366               0 :   if (sPendingEventMode != 0 && !mHasPendingEvent &&
    1367                 :       (mDeflectedCount % sEventProbeRate) == 0) {
    1368               0 :     nsIViewManager* vm = shell->GetViewManager();
    1369               0 :     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
    1370               0 :     nsCOMPtr<nsIWidget> widget;
    1371               0 :     vm->GetRootWidget(getter_AddRefs(widget));
    1372               0 :     mHasPendingEvent = widget && widget->HasPendingInputEvent();
    1373                 :   }
    1374                 : 
    1375               0 :   if (mHasPendingEvent && sPendingEventMode == 2) {
    1376               0 :     return NS_ERROR_HTMLPARSER_INTERRUPTED;
    1377                 :   }
    1378                 : 
    1379                 :   // Have we processed enough tokens to check time?
    1380               0 :   if (!mHasPendingEvent &&
    1381                 :       mDeflectedCount < PRUint32(mDynamicLowerValue ? sInteractiveDeflectCount :
    1382                 :                                                       sPerfDeflectCount)) {
    1383               0 :     return NS_OK;
    1384                 :   }
    1385                 : 
    1386               0 :   mDeflectedCount = 0;
    1387                 : 
    1388                 :   // Check if it's time to return to the main event loop
    1389               0 :   if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
    1390               0 :     return NS_ERROR_HTMLPARSER_INTERRUPTED;
    1391                 :   }
    1392                 : 
    1393               0 :   return NS_OK;
    1394                 : }
    1395                 : 
    1396                 : //----------------------------------------------------------------------
    1397                 : 
    1398                 : void
    1399               0 : nsContentSink::FavorPerformanceHint(bool perfOverStarvation, PRUint32 starvationDelay)
    1400                 : {
    1401                 :   static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    1402               0 :   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
    1403               0 :   if (appShell)
    1404               0 :     appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
    1405               0 : }
    1406                 : 
    1407                 : void
    1408            3994 : nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
    1409                 : {
    1410                 :   // Remember nested updates from updates that we started.
    1411            3994 :   if (mInNotification > 0 && mUpdatesInNotification < 2) {
    1412            3008 :     ++mUpdatesInNotification;
    1413                 :   }
    1414                 : 
    1415                 :   // If we're in a script and we didn't do the notification,
    1416                 :   // something else in the script processing caused the
    1417                 :   // notification to occur. Since this could result in frame
    1418                 :   // creation, make sure we've flushed everything before we
    1419                 :   // continue.
    1420                 : 
    1421            3994 :   if (!mInNotification++) {
    1422             986 :     FlushTags();
    1423                 :   }
    1424            3994 : }
    1425                 : 
    1426                 : void
    1427            3994 : nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
    1428                 : {
    1429                 :   // If we're in a script and we didn't do the notification,
    1430                 :   // something else in the script processing caused the
    1431                 :   // notification to occur. Update our notion of how much
    1432                 :   // has been flushed to include any new content if ending
    1433                 :   // this update leaves us not inside a notification.
    1434            3994 :   if (!--mInNotification) {
    1435             986 :     UpdateChildCounts();
    1436                 :   }
    1437            3994 : }
    1438                 : 
    1439                 : void
    1440            1038 : nsContentSink::DidBuildModelImpl(bool aTerminated)
    1441                 : {
    1442            1038 :   if (mDocument && !aTerminated) {
    1443             976 :     mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
    1444                 :   }
    1445                 : 
    1446            1038 :   if (mScriptLoader) {
    1447            1038 :     mScriptLoader->ParsingComplete(aTerminated);
    1448                 :   }
    1449                 : 
    1450            1038 :   if (!mDocument->HaveFiredDOMTitleChange()) {
    1451            1038 :     mDocument->NotifyPossibleTitleChange(false);
    1452                 :   }
    1453                 : 
    1454                 :   // Cancel a timer if we had one out there
    1455            1038 :   if (mNotificationTimer) {
    1456             976 :     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
    1457                 :                ("nsContentSink::DidBuildModel: canceling notification "
    1458                 :                 "timeout"));
    1459             976 :     mNotificationTimer->Cancel();
    1460             976 :     mNotificationTimer = 0;
    1461                 :   }     
    1462            1038 : }
    1463                 : 
    1464                 : void
    1465            1272 : nsContentSink::DropParserAndPerfHint(void)
    1466                 : {
    1467            1272 :   if (!mParser) {
    1468                 :     // Make sure we don't unblock unload too many times
    1469               0 :     return;
    1470                 :   }
    1471                 :   
    1472                 :   // Ref. Bug 49115
    1473                 :   // Do this hack to make sure that the parser
    1474                 :   // doesn't get destroyed, accidently, before
    1475                 :   // the circularity, between sink & parser, is
    1476                 :   // actually broken.
    1477                 :   // Drop our reference to the parser to get rid of a circular
    1478                 :   // reference.
    1479            2544 :   nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
    1480                 : 
    1481            1272 :   if (mDynamicLowerValue) {
    1482                 :     // Reset the performance hint which was set to FALSE
    1483                 :     // when mDynamicLowerValue was set.
    1484               0 :     FavorPerformanceHint(true, 0);
    1485                 :   }
    1486                 : 
    1487            1272 :   if (!mRunsToCompletion) {
    1488            1038 :     mDocument->UnblockOnload(true);
    1489                 :   }
    1490                 : }
    1491                 : 
    1492                 : bool
    1493            2154 : nsContentSink::IsScriptExecutingImpl()
    1494                 : {
    1495            2154 :   return !!mScriptLoader->GetCurrentScript();
    1496                 : }
    1497                 : 
    1498                 : nsresult
    1499            2153 : nsContentSink::WillParseImpl(void)
    1500                 : {
    1501            2153 :   if (mRunsToCompletion) {
    1502               0 :     return NS_OK;
    1503                 :   }
    1504                 : 
    1505            2153 :   nsIPresShell *shell = mDocument->GetShell();
    1506            2153 :   if (!shell) {
    1507            2153 :     return NS_OK;
    1508                 :   }
    1509                 : 
    1510               0 :   PRUint32 currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
    1511                 : 
    1512               0 :   if (sEnablePerfMode == 0) {
    1513               0 :     nsIViewManager* vm = shell->GetViewManager();
    1514               0 :     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
    1515                 :     PRUint32 lastEventTime;
    1516               0 :     vm->GetLastUserEventTime(lastEventTime);
    1517                 : 
    1518                 :     bool newDynLower =
    1519                 :       (currentTime - mBeginLoadTime) > PRUint32(sInitialPerfTime) &&
    1520               0 :       (currentTime - lastEventTime) < PRUint32(sInteractiveTime);
    1521                 :     
    1522               0 :     if (mDynamicLowerValue != newDynLower) {
    1523               0 :       FavorPerformanceHint(!newDynLower, 0);
    1524               0 :       mDynamicLowerValue = newDynLower;
    1525                 :     }
    1526                 :   }
    1527                 :   
    1528               0 :   mDeflectedCount = 0;
    1529               0 :   mHasPendingEvent = false;
    1530                 : 
    1531                 :   mCurrentParseEndTime = currentTime +
    1532               0 :     (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
    1533                 : 
    1534               0 :   return NS_OK;
    1535                 : }
    1536                 : 
    1537                 : void
    1538            1038 : nsContentSink::WillBuildModelImpl()
    1539                 : {
    1540            1038 :   if (!mRunsToCompletion) {
    1541            1038 :     mDocument->BlockOnload();
    1542                 : 
    1543            1038 :     mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
    1544                 :   }
    1545                 : 
    1546            1038 :   mDocument->ResetScrolledToRefAlready();
    1547                 : 
    1548            1038 :   if (mProcessLinkHeaderEvent.get()) {
    1549               0 :     mProcessLinkHeaderEvent.Revoke();
    1550                 : 
    1551               0 :     DoProcessLinkHeader();
    1552                 :   }
    1553            1038 : }
    1554                 : 
    1555                 : /* static */
    1556                 : void
    1557            1282 : nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
    1558                 : {
    1559                 :   nsCOMPtr<nsIObserverService> observerService =
    1560            2564 :     mozilla::services::GetObserverService();
    1561            1282 :   if (observerService) {
    1562            2564 :     nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
    1563            1282 :     observerService->
    1564                 :       NotifyObservers(domDoc, "document-element-inserted",
    1565            1282 :                       EmptyString().get());
    1566                 :   }
    1567            5674 : }

Generated by: LCOV version 1.7