content/base/src/nsContentSink.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsContentSink.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1552 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * Base class for the XML and HTML content sinks, which construct a
    1.12 + * DOM based on information from the parser.
    1.13 + */
    1.14 +
    1.15 +#include "nsContentSink.h"
    1.16 +#include "nsScriptLoader.h"
    1.17 +#include "nsIDocument.h"
    1.18 +#include "nsIDOMDocument.h"
    1.19 +#include "mozilla/css/Loader.h"
    1.20 +#include "nsStyleLinkElement.h"
    1.21 +#include "nsIDocShell.h"
    1.22 +#include "nsILoadContext.h"
    1.23 +#include "nsCPrefetchService.h"
    1.24 +#include "nsIURI.h"
    1.25 +#include "nsNetUtil.h"
    1.26 +#include "nsIHttpChannel.h"
    1.27 +#include "nsIContent.h"
    1.28 +#include "nsIPresShell.h"
    1.29 +#include "nsPresContext.h"
    1.30 +#include "nsViewManager.h"
    1.31 +#include "nsIAtom.h"
    1.32 +#include "nsGkAtoms.h"
    1.33 +#include "nsNetCID.h"
    1.34 +#include "nsIOfflineCacheUpdate.h"
    1.35 +#include "nsIApplicationCache.h"
    1.36 +#include "nsIApplicationCacheContainer.h"
    1.37 +#include "nsIApplicationCacheChannel.h"
    1.38 +#include "nsIScriptSecurityManager.h"
    1.39 +#include "nsICookieService.h"
    1.40 +#include "nsContentUtils.h"
    1.41 +#include "nsNodeInfoManager.h"
    1.42 +#include "nsIAppShell.h"
    1.43 +#include "nsIWidget.h"
    1.44 +#include "nsWidgetsCID.h"
    1.45 +#include "nsIDOMNode.h"
    1.46 +#include "mozAutoDocUpdate.h"
    1.47 +#include "nsIWebNavigation.h"
    1.48 +#include "nsGenericHTMLElement.h"
    1.49 +#include "nsHTMLDNSPrefetch.h"
    1.50 +#include "nsIObserverService.h"
    1.51 +#include "mozilla/Preferences.h"
    1.52 +#include "nsParserConstants.h"
    1.53 +
    1.54 +using namespace mozilla;
    1.55 +
    1.56 +PRLogModuleInfo* gContentSinkLogModuleInfo;
    1.57 +
    1.58 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
    1.59 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
    1.60 +
    1.61 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
    1.62 +  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
    1.63 +  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    1.64 +  NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
    1.65 +  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
    1.66 +  NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
    1.67 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
    1.68 +NS_INTERFACE_MAP_END
    1.69 +
    1.70 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
    1.71 +
    1.72 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
    1.73 +  if (tmp->mDocument) {
    1.74 +    tmp->mDocument->RemoveObserver(tmp);
    1.75 +  }
    1.76 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
    1.77 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
    1.78 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
    1.79 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptLoader)
    1.80 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1.81 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
    1.82 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
    1.83 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
    1.84 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
    1.85 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
    1.86 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1.87 +
    1.88 +
    1.89 +nsContentSink::nsContentSink()
    1.90 +{
    1.91 +  // We have a zeroing operator new
    1.92 +  NS_ASSERTION(!mLayoutStarted, "What?");
    1.93 +  NS_ASSERTION(!mDynamicLowerValue, "What?");
    1.94 +  NS_ASSERTION(!mParsing, "What?");
    1.95 +  NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
    1.96 +  NS_ASSERTION(mDeflectedCount == 0, "What?");
    1.97 +  NS_ASSERTION(!mDroppedTimer, "What?");
    1.98 +  NS_ASSERTION(mInMonolithicContainer == 0, "What?");
    1.99 +  NS_ASSERTION(mInNotification == 0, "What?");
   1.100 +  NS_ASSERTION(!mDeferredLayoutStart, "What?");
   1.101 +
   1.102 +#ifdef DEBUG
   1.103 +  if (!gContentSinkLogModuleInfo) {
   1.104 +    gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink");
   1.105 +  }
   1.106 +#endif
   1.107 +}
   1.108 +
   1.109 +nsContentSink::~nsContentSink()
   1.110 +{
   1.111 +  if (mDocument) {
   1.112 +    // Remove ourselves just to be safe, though we really should have
   1.113 +    // been removed in DidBuildModel if everything worked right.
   1.114 +    mDocument->RemoveObserver(this);
   1.115 +  }
   1.116 +}
   1.117 +
   1.118 +bool    nsContentSink::sNotifyOnTimer;
   1.119 +int32_t nsContentSink::sBackoffCount;
   1.120 +int32_t nsContentSink::sNotificationInterval;
   1.121 +int32_t nsContentSink::sInteractiveDeflectCount;
   1.122 +int32_t nsContentSink::sPerfDeflectCount;
   1.123 +int32_t nsContentSink::sPendingEventMode;
   1.124 +int32_t nsContentSink::sEventProbeRate;
   1.125 +int32_t nsContentSink::sInteractiveParseTime;
   1.126 +int32_t nsContentSink::sPerfParseTime;
   1.127 +int32_t nsContentSink::sInteractiveTime;
   1.128 +int32_t nsContentSink::sInitialPerfTime;
   1.129 +int32_t nsContentSink::sEnablePerfMode;
   1.130 +
   1.131 +void
   1.132 +nsContentSink::InitializeStatics()
   1.133 +{
   1.134 +  Preferences::AddBoolVarCache(&sNotifyOnTimer,
   1.135 +                               "content.notify.ontimer", true);
   1.136 +  // -1 means never.
   1.137 +  Preferences::AddIntVarCache(&sBackoffCount,
   1.138 +                              "content.notify.backoffcount", -1);
   1.139 +  // The gNotificationInterval has a dramatic effect on how long it
   1.140 +  // takes to initially display content for slow connections.
   1.141 +  // The current value provides good
   1.142 +  // incremental display of content without causing an increase
   1.143 +  // in page load time. If this value is set below 1/10 of second
   1.144 +  // it starts to impact page load performance.
   1.145 +  // see bugzilla bug 72138 for more info.
   1.146 +  Preferences::AddIntVarCache(&sNotificationInterval,
   1.147 +                              "content.notify.interval", 120000);
   1.148 +  Preferences::AddIntVarCache(&sInteractiveDeflectCount,
   1.149 +                              "content.sink.interactive_deflect_count", 0);
   1.150 +  Preferences::AddIntVarCache(&sPerfDeflectCount,
   1.151 +                              "content.sink.perf_deflect_count", 200);
   1.152 +  Preferences::AddIntVarCache(&sPendingEventMode,
   1.153 +                              "content.sink.pending_event_mode", 1);
   1.154 +  Preferences::AddIntVarCache(&sEventProbeRate,
   1.155 +                              "content.sink.event_probe_rate", 1);
   1.156 +  Preferences::AddIntVarCache(&sInteractiveParseTime,
   1.157 +                              "content.sink.interactive_parse_time", 3000);
   1.158 +  Preferences::AddIntVarCache(&sPerfParseTime,
   1.159 +                              "content.sink.perf_parse_time", 360000);
   1.160 +  Preferences::AddIntVarCache(&sInteractiveTime,
   1.161 +                              "content.sink.interactive_time", 750000);
   1.162 +  Preferences::AddIntVarCache(&sInitialPerfTime,
   1.163 +                              "content.sink.initial_perf_time", 2000000);
   1.164 +  Preferences::AddIntVarCache(&sEnablePerfMode,
   1.165 +                              "content.sink.enable_perf_mode", 0);
   1.166 +}
   1.167 +
   1.168 +nsresult
   1.169 +nsContentSink::Init(nsIDocument* aDoc,
   1.170 +                    nsIURI* aURI,
   1.171 +                    nsISupports* aContainer,
   1.172 +                    nsIChannel* aChannel)
   1.173 +{
   1.174 +  NS_PRECONDITION(aDoc, "null ptr");
   1.175 +  NS_PRECONDITION(aURI, "null ptr");
   1.176 +
   1.177 +  if (!aDoc || !aURI) {
   1.178 +    return NS_ERROR_NULL_POINTER;
   1.179 +  }
   1.180 +
   1.181 +  mDocument = aDoc;
   1.182 +
   1.183 +  mDocumentURI = aURI;
   1.184 +  mDocShell = do_QueryInterface(aContainer);
   1.185 +  mScriptLoader = mDocument->ScriptLoader();
   1.186 +
   1.187 +  if (!mRunsToCompletion) {
   1.188 +    if (mDocShell) {
   1.189 +      uint32_t loadType = 0;
   1.190 +      mDocShell->GetLoadType(&loadType);
   1.191 +      mDocument->SetChangeScrollPosWhenScrollingToRef(
   1.192 +        (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
   1.193 +    }
   1.194 +
   1.195 +    ProcessHTTPHeaders(aChannel);
   1.196 +  }
   1.197 +
   1.198 +  mCSSLoader = aDoc->CSSLoader();
   1.199 +
   1.200 +  mNodeInfoManager = aDoc->NodeInfoManager();
   1.201 +
   1.202 +  mBackoffCount = sBackoffCount;
   1.203 +
   1.204 +  if (sEnablePerfMode != 0) {
   1.205 +    mDynamicLowerValue = sEnablePerfMode == 1;
   1.206 +    FavorPerformanceHint(!mDynamicLowerValue, 0);
   1.207 +  }
   1.208 +
   1.209 +  return NS_OK;
   1.210 +}
   1.211 +
   1.212 +NS_IMETHODIMP
   1.213 +nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
   1.214 +                                bool aWasAlternate,
   1.215 +                                nsresult aStatus)
   1.216 +{
   1.217 +  NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
   1.218 +  if (!aWasAlternate) {
   1.219 +    NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
   1.220 +    --mPendingSheetCount;
   1.221 +
   1.222 +    if (mPendingSheetCount == 0 &&
   1.223 +        (mDeferredLayoutStart || mDeferredFlushTags)) {
   1.224 +      if (mDeferredFlushTags) {
   1.225 +        FlushTags();
   1.226 +      }
   1.227 +      if (mDeferredLayoutStart) {
   1.228 +        // We might not have really started layout, since this sheet was still
   1.229 +        // loading.  Do it now.  Probably doesn't matter whether we do this
   1.230 +        // before or after we unblock scripts, but before feels saner.  Note
   1.231 +        // that if mDeferredLayoutStart is true, that means any subclass
   1.232 +        // StartLayout() stuff that needs to happen has already happened, so we
   1.233 +        // don't need to worry about it.
   1.234 +        StartLayout(false);
   1.235 +      }
   1.236 +
   1.237 +      // Go ahead and try to scroll to our ref if we have one
   1.238 +      ScrollToRef();
   1.239 +    }
   1.240 +    
   1.241 +    mScriptLoader->RemoveExecuteBlocker();
   1.242 +  }
   1.243 +
   1.244 +  return NS_OK;
   1.245 +}
   1.246 +
   1.247 +nsresult
   1.248 +nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
   1.249 +{
   1.250 +  nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
   1.251 +  
   1.252 +  if (!httpchannel) {
   1.253 +    return NS_OK;
   1.254 +  }
   1.255 +
   1.256 +  // Note that the only header we care about is the "link" header, since we
   1.257 +  // have all the infrastructure for kicking off stylesheet loads.
   1.258 +  
   1.259 +  nsAutoCString linkHeader;
   1.260 +  
   1.261 +  nsresult rv = httpchannel->GetResponseHeader(NS_LITERAL_CSTRING("link"),
   1.262 +                                               linkHeader);
   1.263 +  if (NS_SUCCEEDED(rv) && !linkHeader.IsEmpty()) {
   1.264 +    mDocument->SetHeaderData(nsGkAtoms::link,
   1.265 +                             NS_ConvertASCIItoUTF16(linkHeader));
   1.266 +
   1.267 +    NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
   1.268 +                 "Already dispatched an event?");
   1.269 +
   1.270 +    mProcessLinkHeaderEvent =
   1.271 +      NS_NewNonOwningRunnableMethod(this,
   1.272 +        &nsContentSink::DoProcessLinkHeader);
   1.273 +    rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get());
   1.274 +    if (NS_FAILED(rv)) {
   1.275 +      mProcessLinkHeaderEvent.Forget();
   1.276 +    }
   1.277 +  }
   1.278 +  
   1.279 +  return NS_OK;
   1.280 +}
   1.281 +
   1.282 +nsresult
   1.283 +nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
   1.284 +                                 nsIContent* aContent)
   1.285 +{
   1.286 +  nsresult rv = NS_OK;
   1.287 +  // necko doesn't process headers coming in from the parser
   1.288 +
   1.289 +  mDocument->SetHeaderData(aHeader, aValue);
   1.290 +
   1.291 +  if (aHeader == nsGkAtoms::setcookie) {
   1.292 +    // Note: Necko already handles cookies set via the channel.  We can't just
   1.293 +    // call SetCookie on the channel because we want to do some security checks
   1.294 +    // here.
   1.295 +    nsCOMPtr<nsICookieService> cookieServ =
   1.296 +      do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv);
   1.297 +    if (NS_FAILED(rv)) {
   1.298 +      return rv;
   1.299 +    }
   1.300 +
   1.301 +    // Get a URI from the document principal
   1.302 +
   1.303 +    // We use the original codebase in case the codebase was changed
   1.304 +    // by SetDomain
   1.305 +
   1.306 +    // Note that a non-codebase principal (eg the system principal) will return
   1.307 +    // a null URI.
   1.308 +    nsCOMPtr<nsIURI> codebaseURI;
   1.309 +    rv = mDocument->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
   1.310 +    NS_ENSURE_TRUE(codebaseURI, rv);
   1.311 +
   1.312 +    nsCOMPtr<nsIChannel> channel;
   1.313 +    if (mParser) {
   1.314 +      mParser->GetChannel(getter_AddRefs(channel));
   1.315 +    }
   1.316 +
   1.317 +    rv = cookieServ->SetCookieString(codebaseURI,
   1.318 +                                     nullptr,
   1.319 +                                     NS_ConvertUTF16toUTF8(aValue).get(),
   1.320 +                                     channel);
   1.321 +    if (NS_FAILED(rv)) {
   1.322 +      return rv;
   1.323 +    }
   1.324 +  }
   1.325 +  else if (aHeader == nsGkAtoms::msthemecompatible) {
   1.326 +    // Disable theming for the presshell if the value is no.
   1.327 +    // XXXbz don't we want to support this as an HTTP header too?
   1.328 +    nsAutoString value(aValue);
   1.329 +    if (value.LowerCaseEqualsLiteral("no")) {
   1.330 +      nsIPresShell* shell = mDocument->GetShell();
   1.331 +      if (shell) {
   1.332 +        shell->DisableThemeSupport();
   1.333 +      }
   1.334 +    }
   1.335 +  }
   1.336 +
   1.337 +  return rv;
   1.338 +}
   1.339 +
   1.340 +
   1.341 +void
   1.342 +nsContentSink::DoProcessLinkHeader()
   1.343 +{
   1.344 +  nsAutoString value;
   1.345 +  mDocument->GetHeaderData(nsGkAtoms::link, value);
   1.346 +  ProcessLinkHeader(value);
   1.347 +}
   1.348 +
   1.349 +// check whether the Link header field applies to the context resource
   1.350 +// see <http://tools.ietf.org/html/rfc5988#section-5.2>
   1.351 +
   1.352 +bool
   1.353 +nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
   1.354 +{
   1.355 +  if (aAnchor.IsEmpty()) {
   1.356 +    // anchor parameter not present or empty -> same document reference
   1.357 +    return true;
   1.358 +  }
   1.359 +
   1.360 +  nsIURI* docUri = mDocument->GetDocumentURI();
   1.361 +
   1.362 +  // the document URI might contain a fragment identifier ("#...')
   1.363 +  // we want to ignore that because it's invisible to the server
   1.364 +  // and just affects the local interpretation in the recipient
   1.365 +  nsCOMPtr<nsIURI> contextUri;
   1.366 +  nsresult rv = docUri->CloneIgnoringRef(getter_AddRefs(contextUri));
   1.367 +  
   1.368 +  if (NS_FAILED(rv)) {
   1.369 +    // copying failed
   1.370 +    return false;
   1.371 +  }
   1.372 +  
   1.373 +  // resolve anchor against context    
   1.374 +  nsCOMPtr<nsIURI> resolvedUri;
   1.375 +  rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor,
   1.376 +      nullptr, contextUri);
   1.377 +  
   1.378 +  if (NS_FAILED(rv)) {
   1.379 +    // resolving failed
   1.380 +    return false;
   1.381 +  }
   1.382 +
   1.383 +  bool same;
   1.384 +  rv = contextUri->Equals(resolvedUri, &same); 
   1.385 +  if (NS_FAILED(rv)) {
   1.386 +    // comparison failed
   1.387 +    return false;
   1.388 +  }
   1.389 +
   1.390 +  return same;
   1.391 +}
   1.392 +
   1.393 +// Decode a parameter value using the encoding defined in RFC 5987 (in place)
   1.394 +//
   1.395 +//   charset  "'" [ language ] "'" value-chars
   1.396 +//
   1.397 +// returns true when decoding happened successfully (otherwise leaves
   1.398 +// passed value alone)
   1.399 +bool
   1.400 +nsContentSink::Decode5987Format(nsAString& aEncoded) {
   1.401 +
   1.402 +  nsresult rv;
   1.403 +  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
   1.404 +  do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
   1.405 +  if (NS_FAILED(rv))
   1.406 +    return false;
   1.407 +
   1.408 +  nsAutoCString asciiValue;
   1.409 +
   1.410 +  const char16_t* encstart = aEncoded.BeginReading();
   1.411 +  const char16_t* encend = aEncoded.EndReading();
   1.412 +
   1.413 +  // create a plain ASCII string, aborting if we can't do that
   1.414 +  // converted form is always shorter than input
   1.415 +  while (encstart != encend) {
   1.416 +    if (*encstart > 0 && *encstart < 128) {
   1.417 +      asciiValue.Append((char)*encstart);
   1.418 +    } else {
   1.419 +      return false;
   1.420 +    }
   1.421 +    encstart++;
   1.422 +  }
   1.423 +
   1.424 +  nsAutoString decoded;
   1.425 +  nsAutoCString language;
   1.426 +
   1.427 +  rv = mimehdrpar->DecodeRFC5987Param(asciiValue, language, decoded);
   1.428 +  if (NS_FAILED(rv))
   1.429 +    return false;
   1.430 +
   1.431 +  aEncoded = decoded;
   1.432 +  return true;
   1.433 +}
   1.434 +
   1.435 +nsresult
   1.436 +nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
   1.437 +{
   1.438 +  nsresult rv = NS_OK;
   1.439 +
   1.440 +  // keep track where we are within the header field
   1.441 +  bool seenParameters = false;
   1.442 +
   1.443 +  // parse link content and call process style link
   1.444 +  nsAutoString href;
   1.445 +  nsAutoString rel;
   1.446 +  nsAutoString title;
   1.447 +  nsAutoString titleStar;
   1.448 +  nsAutoString type;
   1.449 +  nsAutoString media;
   1.450 +  nsAutoString anchor;
   1.451 +
   1.452 +  // copy to work buffer
   1.453 +  nsAutoString stringList(aLinkData);
   1.454 +
   1.455 +  // put an extra null at the end
   1.456 +  stringList.Append(kNullCh);
   1.457 +
   1.458 +  char16_t* start = stringList.BeginWriting();
   1.459 +  char16_t* end   = start;
   1.460 +  char16_t* last  = start;
   1.461 +  char16_t  endCh;
   1.462 +
   1.463 +  while (*start != kNullCh) {
   1.464 +    // skip leading space
   1.465 +    while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) {
   1.466 +      ++start;
   1.467 +    }
   1.468 +
   1.469 +    end = start;
   1.470 +    last = end - 1;
   1.471 +
   1.472 +    bool wasQuotedString = false;
   1.473 +    
   1.474 +    // look for semicolon or comma
   1.475 +    while (*end != kNullCh && *end != kSemicolon && *end != kComma) {
   1.476 +      char16_t ch = *end;
   1.477 +
   1.478 +      if (ch == kQuote || ch == kLessThan) {
   1.479 +        // quoted string
   1.480 +
   1.481 +        char16_t quote = ch;
   1.482 +        if (quote == kLessThan) {
   1.483 +          quote = kGreaterThan;
   1.484 +        }
   1.485 +        
   1.486 +        wasQuotedString = (ch == kQuote);
   1.487 +        
   1.488 +        char16_t* closeQuote = (end + 1);
   1.489 +
   1.490 +        // seek closing quote
   1.491 +        while (*closeQuote != kNullCh && quote != *closeQuote) {
   1.492 +          // in quoted-string, "\" is an escape character
   1.493 +          if (wasQuotedString && *closeQuote == kBackSlash && *(closeQuote + 1) != kNullCh) {
   1.494 +            ++closeQuote;
   1.495 +          }
   1.496 +
   1.497 +          ++closeQuote;
   1.498 +        }
   1.499 +
   1.500 +        if (quote == *closeQuote) {
   1.501 +          // found closer
   1.502 +
   1.503 +          // skip to close quote
   1.504 +          end = closeQuote;
   1.505 +
   1.506 +          last = end - 1;
   1.507 +
   1.508 +          ch = *(end + 1);
   1.509 +
   1.510 +          if (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   1.511 +            // end string here
   1.512 +            *(++end) = kNullCh;
   1.513 +
   1.514 +            ch = *(end + 1);
   1.515 +
   1.516 +            // keep going until semi or comma
   1.517 +            while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   1.518 +              ++end;
   1.519 +
   1.520 +              ch = *end;
   1.521 +            }
   1.522 +          }
   1.523 +        }
   1.524 +      }
   1.525 +
   1.526 +      ++end;
   1.527 +      ++last;
   1.528 +    }
   1.529 +
   1.530 +    endCh = *end;
   1.531 +
   1.532 +    // end string here
   1.533 +    *end = kNullCh;
   1.534 +
   1.535 +    if (start < end) {
   1.536 +      if ((*start == kLessThan) && (*last == kGreaterThan)) {
   1.537 +        *last = kNullCh;
   1.538 +
   1.539 +        // first instance of <...> wins
   1.540 +        // also, do not allow hrefs after the first param was seen
   1.541 +        if (href.IsEmpty() && !seenParameters) {
   1.542 +          href = (start + 1);
   1.543 +          href.StripWhitespace();
   1.544 +        }
   1.545 +      } else {
   1.546 +        char16_t* equals = start;
   1.547 +        seenParameters = true;
   1.548 +
   1.549 +        while ((*equals != kNullCh) && (*equals != kEqual)) {
   1.550 +          equals++;
   1.551 +        }
   1.552 +
   1.553 +        if (*equals != kNullCh) {
   1.554 +          *equals = kNullCh;
   1.555 +          nsAutoString  attr(start);
   1.556 +          attr.StripWhitespace();
   1.557 +
   1.558 +          char16_t* value = ++equals;
   1.559 +          while (nsCRT::IsAsciiSpace(*value)) {
   1.560 +            value++;
   1.561 +          }
   1.562 +
   1.563 +          if ((*value == kQuote) && (*value == *last)) {
   1.564 +            *last = kNullCh;
   1.565 +            value++;
   1.566 +          }
   1.567 +
   1.568 +          if (wasQuotedString) {
   1.569 +            // unescape in-place
   1.570 +            char16_t* unescaped = value;
   1.571 +            char16_t *src = value;
   1.572 +            
   1.573 +            while (*src != kNullCh) {
   1.574 +              if (*src == kBackSlash && *(src + 1) != kNullCh) {
   1.575 +                src++;
   1.576 +              }
   1.577 +              *unescaped++ = *src++;
   1.578 +            }
   1.579 +
   1.580 +            *unescaped = kNullCh;
   1.581 +          }
   1.582 +          
   1.583 +          if (attr.LowerCaseEqualsLiteral("rel")) {
   1.584 +            if (rel.IsEmpty()) {
   1.585 +              rel = value;
   1.586 +              rel.CompressWhitespace();
   1.587 +            }
   1.588 +          } else if (attr.LowerCaseEqualsLiteral("title")) {
   1.589 +            if (title.IsEmpty()) {
   1.590 +              title = value;
   1.591 +              title.CompressWhitespace();
   1.592 +            }
   1.593 +          } else if (attr.LowerCaseEqualsLiteral("title*")) {
   1.594 +            if (titleStar.IsEmpty() && !wasQuotedString) {
   1.595 +              // RFC 5987 encoding; uses token format only, so skip if we get
   1.596 +              // here with a quoted-string
   1.597 +              nsAutoString tmp;
   1.598 +              tmp = value;
   1.599 +              if (Decode5987Format(tmp)) {
   1.600 +                titleStar = tmp;
   1.601 +                titleStar.CompressWhitespace();
   1.602 +              } else {
   1.603 +                // header value did not parse, throw it away
   1.604 +                titleStar.Truncate();
   1.605 +              }
   1.606 +            }
   1.607 +          } else if (attr.LowerCaseEqualsLiteral("type")) {
   1.608 +            if (type.IsEmpty()) {
   1.609 +              type = value;
   1.610 +              type.StripWhitespace();
   1.611 +            }
   1.612 +          } else if (attr.LowerCaseEqualsLiteral("media")) {
   1.613 +            if (media.IsEmpty()) {
   1.614 +              media = value;
   1.615 +
   1.616 +              // The HTML5 spec is formulated in terms of the CSS3 spec,
   1.617 +              // which specifies that media queries are case insensitive.
   1.618 +              nsContentUtils::ASCIIToLower(media);
   1.619 +            }
   1.620 +          } else if (attr.LowerCaseEqualsLiteral("anchor")) {
   1.621 +            if (anchor.IsEmpty()) {
   1.622 +              anchor = value;
   1.623 +              anchor.StripWhitespace();
   1.624 +            }
   1.625 +          }
   1.626 +        }
   1.627 +      }
   1.628 +    }
   1.629 +
   1.630 +    if (endCh == kComma) {
   1.631 +      // hit a comma, process what we've got so far
   1.632 +
   1.633 +      href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   1.634 +      if (!href.IsEmpty() && !rel.IsEmpty()) {
   1.635 +        rv = ProcessLink(anchor, href, rel,
   1.636 +                         // prefer RFC 5987 variant over non-I18zed version
   1.637 +                         titleStar.IsEmpty() ? title : titleStar,
   1.638 +                         type, media);
   1.639 +      }
   1.640 +
   1.641 +      href.Truncate();
   1.642 +      rel.Truncate();
   1.643 +      title.Truncate();
   1.644 +      type.Truncate();
   1.645 +      media.Truncate();
   1.646 +      anchor.Truncate();
   1.647 +      
   1.648 +      seenParameters = false;
   1.649 +    }
   1.650 +
   1.651 +    start = ++end;
   1.652 +  }
   1.653 +                
   1.654 +  href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   1.655 +  if (!href.IsEmpty() && !rel.IsEmpty()) {
   1.656 +    rv = ProcessLink(anchor, href, rel,
   1.657 +                     // prefer RFC 5987 variant over non-I18zed version
   1.658 +                     titleStar.IsEmpty() ? title : titleStar,
   1.659 +                     type, media);
   1.660 +  }
   1.661 +
   1.662 +  return rv;
   1.663 +}
   1.664 +
   1.665 +
   1.666 +nsresult
   1.667 +nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
   1.668 +                           const nsSubstring& aRel, const nsSubstring& aTitle,
   1.669 +                           const nsSubstring& aType, const nsSubstring& aMedia)
   1.670 +{
   1.671 +  uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel);
   1.672 +
   1.673 +  // The link relation may apply to a different resource, specified
   1.674 +  // in the anchor parameter. For the link relations supported so far,
   1.675 +  // we simply abort if the link applies to a resource different to the
   1.676 +  // one we've loaded
   1.677 +  if (!LinkContextIsOurDocument(aAnchor)) {
   1.678 +    return NS_OK;
   1.679 +  }
   1.680 +  
   1.681 +  bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
   1.682 +  // prefetch href if relation is "next" or "prefetch"
   1.683 +  if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
   1.684 +    PrefetchHref(aHref, mDocument, hasPrefetch);
   1.685 +  }
   1.686 +
   1.687 +  if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::eDNS_PREFETCH)) {
   1.688 +    PrefetchDNS(aHref);
   1.689 +  }
   1.690 +
   1.691 +  // is it a stylesheet link?
   1.692 +  if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
   1.693 +    return NS_OK;
   1.694 +  }
   1.695 +
   1.696 +  bool isAlternate = linkTypes & nsStyleLinkElement::eALTERNATE;
   1.697 +  return ProcessStyleLink(nullptr, aHref, isAlternate, aTitle, aType,
   1.698 +                          aMedia);
   1.699 +}
   1.700 +
   1.701 +nsresult
   1.702 +nsContentSink::ProcessStyleLink(nsIContent* aElement,
   1.703 +                                const nsSubstring& aHref,
   1.704 +                                bool aAlternate,
   1.705 +                                const nsSubstring& aTitle,
   1.706 +                                const nsSubstring& aType,
   1.707 +                                const nsSubstring& aMedia)
   1.708 +{
   1.709 +  if (aAlternate && aTitle.IsEmpty()) {
   1.710 +    // alternates must have title return without error, for now
   1.711 +    return NS_OK;
   1.712 +  }
   1.713 +
   1.714 +  nsAutoString  mimeType;
   1.715 +  nsAutoString  params;
   1.716 +  nsContentUtils::SplitMimeType(aType, mimeType, params);
   1.717 +
   1.718 +  // see bug 18817
   1.719 +  if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
   1.720 +    // Unknown stylesheet language
   1.721 +    return NS_OK;
   1.722 +  }
   1.723 +
   1.724 +  nsCOMPtr<nsIURI> url;
   1.725 +  nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
   1.726 +                          mDocument->GetDocBaseURI());
   1.727 +  
   1.728 +  if (NS_FAILED(rv)) {
   1.729 +    // The URI is bad, move along, don't propagate the error (for now)
   1.730 +    return NS_OK;
   1.731 +  }
   1.732 +
   1.733 +  NS_ASSERTION(!aElement ||
   1.734 +               aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
   1.735 +               "We only expect processing instructions here");
   1.736 +
   1.737 +  // If this is a fragment parser, we don't want to observe.
   1.738 +  // We don't support CORS for processing instructions
   1.739 +  bool isAlternate;
   1.740 +  rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
   1.741 +                                 CORS_NONE,
   1.742 +                                 mRunsToCompletion ? nullptr : this, &isAlternate);
   1.743 +  NS_ENSURE_SUCCESS(rv, rv);
   1.744 +  
   1.745 +  if (!isAlternate && !mRunsToCompletion) {
   1.746 +    ++mPendingSheetCount;
   1.747 +    mScriptLoader->AddExecuteBlocker();
   1.748 +  }
   1.749 +
   1.750 +  return NS_OK;
   1.751 +}
   1.752 +
   1.753 +
   1.754 +nsresult
   1.755 +nsContentSink::ProcessMETATag(nsIContent* aContent)
   1.756 +{
   1.757 +  NS_ASSERTION(aContent, "missing meta-element");
   1.758 +
   1.759 +  nsresult rv = NS_OK;
   1.760 +
   1.761 +  // set any HTTP-EQUIV data into document's header data as well as url
   1.762 +  nsAutoString header;
   1.763 +  aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
   1.764 +  if (!header.IsEmpty()) {
   1.765 +    nsAutoString result;
   1.766 +    aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
   1.767 +    if (!result.IsEmpty()) {
   1.768 +      nsContentUtils::ASCIIToLower(header);
   1.769 +      nsCOMPtr<nsIAtom> fieldAtom(do_GetAtom(header));
   1.770 +      rv = ProcessHeaderData(fieldAtom, result, aContent); 
   1.771 +    }
   1.772 +  }
   1.773 +  NS_ENSURE_SUCCESS(rv, rv);
   1.774 +
   1.775 +  if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
   1.776 +                            nsGkAtoms::handheldFriendly, eIgnoreCase)) {
   1.777 +    nsAutoString result;
   1.778 +    aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
   1.779 +    if (!result.IsEmpty()) {
   1.780 +      nsContentUtils::ASCIIToLower(result);
   1.781 +      mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
   1.782 +    }
   1.783 +  }
   1.784 +
   1.785 +  return rv;
   1.786 +}
   1.787 +
   1.788 +
   1.789 +void
   1.790 +nsContentSink::PrefetchHref(const nsAString &aHref,
   1.791 +                            nsINode *aSource,
   1.792 +                            bool aExplicit)
   1.793 +{
   1.794 +  //
   1.795 +  // SECURITY CHECK: disable prefetching from mailnews!
   1.796 +  //
   1.797 +  // walk up the docshell tree to see if any containing
   1.798 +  // docshell are of type MAIL.
   1.799 +  //
   1.800 +  if (!mDocShell)
   1.801 +    return;
   1.802 +
   1.803 +  nsCOMPtr<nsIDocShell> docshell = mDocShell;
   1.804 +
   1.805 +  nsCOMPtr<nsIDocShellTreeItem> parentItem;
   1.806 +  do {
   1.807 +    uint32_t appType = 0;
   1.808 +    nsresult rv = docshell->GetAppType(&appType);
   1.809 +    if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
   1.810 +      return; // do not prefetch from mailnews
   1.811 +    docshell->GetParent(getter_AddRefs(parentItem));
   1.812 +    if (parentItem) {
   1.813 +      docshell = do_QueryInterface(parentItem);
   1.814 +      if (!docshell) {
   1.815 +        NS_ERROR("cannot get a docshell from a treeItem!");
   1.816 +        return;
   1.817 +      }
   1.818 +    }
   1.819 +  } while (parentItem);
   1.820 +  
   1.821 +  // OK, we passed the security check...
   1.822 +  
   1.823 +  nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
   1.824 +  if (prefetchService) {
   1.825 +    // construct URI using document charset
   1.826 +    const nsACString &charset = mDocument->GetDocumentCharacterSet();
   1.827 +    nsCOMPtr<nsIURI> uri;
   1.828 +    NS_NewURI(getter_AddRefs(uri), aHref,
   1.829 +              charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
   1.830 +              mDocument->GetDocBaseURI());
   1.831 +    if (uri) {
   1.832 +      nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aSource);
   1.833 +      prefetchService->PrefetchURI(uri, mDocumentURI, domNode, aExplicit);
   1.834 +    }
   1.835 +  }
   1.836 +}
   1.837 +
   1.838 +void
   1.839 +nsContentSink::PrefetchDNS(const nsAString &aHref)
   1.840 +{
   1.841 +  nsAutoString hostname;
   1.842 +
   1.843 +  if (StringBeginsWith(aHref, NS_LITERAL_STRING("//")))  {
   1.844 +    hostname = Substring(aHref, 2);
   1.845 +  }
   1.846 +  else {
   1.847 +    nsCOMPtr<nsIURI> uri;
   1.848 +    NS_NewURI(getter_AddRefs(uri), aHref);
   1.849 +    if (!uri) {
   1.850 +      return;
   1.851 +    }
   1.852 +    nsAutoCString host;
   1.853 +    uri->GetHost(host);
   1.854 +    CopyUTF8toUTF16(host, hostname);
   1.855 +  }
   1.856 +
   1.857 +  if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
   1.858 +    nsHTMLDNSPrefetch::PrefetchLow(hostname);
   1.859 +  }
   1.860 +}
   1.861 +
   1.862 +nsresult
   1.863 +nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
   1.864 +                                 nsIURI *aManifestURI,
   1.865 +                                 bool aFetchedWithHTTPGetOrEquiv,
   1.866 +                                 CacheSelectionAction *aAction)
   1.867 +{
   1.868 +  nsresult rv;
   1.869 +
   1.870 +  *aAction = CACHE_SELECTION_NONE;
   1.871 +
   1.872 +  nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
   1.873 +    do_QueryInterface(mDocument);
   1.874 +  NS_ASSERTION(applicationCacheDocument,
   1.875 +               "mDocument must implement nsIApplicationCacheContainer.");
   1.876 +
   1.877 +  if (aLoadApplicationCache) {
   1.878 +    nsCOMPtr<nsIURI> groupURI;
   1.879 +    rv = aLoadApplicationCache->GetManifestURI(getter_AddRefs(groupURI));
   1.880 +    NS_ENSURE_SUCCESS(rv, rv);
   1.881 +
   1.882 +    bool equal = false;
   1.883 +    rv = groupURI->Equals(aManifestURI, &equal);
   1.884 +    NS_ENSURE_SUCCESS(rv, rv);
   1.885 +
   1.886 +    if (!equal) {
   1.887 +      // This is a foreign entry, force a reload to avoid loading the foreign
   1.888 +      // entry. The entry will be marked as foreign to avoid loading it again.
   1.889 +
   1.890 +      *aAction = CACHE_SELECTION_RELOAD;
   1.891 +    }
   1.892 +    else {
   1.893 +      // The http manifest attribute URI is equal to the manifest URI of
   1.894 +      // the cache the document was loaded from - associate the document with
   1.895 +      // that cache and invoke the cache update process.
   1.896 +#ifdef DEBUG
   1.897 +      nsAutoCString docURISpec, clientID;
   1.898 +      mDocumentURI->GetAsciiSpec(docURISpec);
   1.899 +      aLoadApplicationCache->GetClientID(clientID);
   1.900 +      SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
   1.901 +          ("Selection: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
   1.902 +#endif
   1.903 +
   1.904 +      rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
   1.905 +      NS_ENSURE_SUCCESS(rv, rv);
   1.906 +
   1.907 +      // Document will be added as implicit entry to the cache as part of
   1.908 +      // the update process.
   1.909 +      *aAction = CACHE_SELECTION_UPDATE;
   1.910 +    }
   1.911 +  }
   1.912 +  else {
   1.913 +    // The document was not loaded from an application cache
   1.914 +    // Here we know the manifest has the same origin as the
   1.915 +    // document. There is call to CheckMayLoad() on it above.
   1.916 +
   1.917 +    if (!aFetchedWithHTTPGetOrEquiv) {
   1.918 +      // The document was not loaded using HTTP GET or equivalent
   1.919 +      // method. The spec says to run the cache selection algorithm w/o
   1.920 +      // the manifest specified.
   1.921 +      *aAction = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
   1.922 +    }
   1.923 +    else {
   1.924 +      // Always do an update in this case
   1.925 +      *aAction = CACHE_SELECTION_UPDATE;
   1.926 +    }
   1.927 +  }
   1.928 +
   1.929 +  return NS_OK;
   1.930 +}
   1.931 +
   1.932 +nsresult
   1.933 +nsContentSink::SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
   1.934 +                                           nsIURI **aManifestURI,
   1.935 +                                           CacheSelectionAction *aAction)
   1.936 +{
   1.937 +  *aManifestURI = nullptr;
   1.938 +  *aAction = CACHE_SELECTION_NONE;
   1.939 +
   1.940 +  nsresult rv;
   1.941 +
   1.942 +  if (aLoadApplicationCache) {
   1.943 +    // The document was loaded from an application cache, use that
   1.944 +    // application cache as the document's application cache.
   1.945 +    nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
   1.946 +      do_QueryInterface(mDocument);
   1.947 +    NS_ASSERTION(applicationCacheDocument,
   1.948 +                 "mDocument must implement nsIApplicationCacheContainer.");
   1.949 +
   1.950 +#ifdef DEBUG
   1.951 +    nsAutoCString docURISpec, clientID;
   1.952 +    mDocumentURI->GetAsciiSpec(docURISpec);
   1.953 +    aLoadApplicationCache->GetClientID(clientID);
   1.954 +    SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
   1.955 +        ("Selection, no manifest: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
   1.956 +#endif
   1.957 +
   1.958 +    rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
   1.959 +    NS_ENSURE_SUCCESS(rv, rv);
   1.960 +
   1.961 +    // Return the uri and invoke the update process for the selected
   1.962 +    // application cache.
   1.963 +    rv = aLoadApplicationCache->GetManifestURI(aManifestURI);
   1.964 +    NS_ENSURE_SUCCESS(rv, rv);
   1.965 +
   1.966 +    *aAction = CACHE_SELECTION_UPDATE;
   1.967 +  }
   1.968 +
   1.969 +  return NS_OK;
   1.970 +}
   1.971 +
   1.972 +void
   1.973 +nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
   1.974 +{
   1.975 +  // Only check the manifest for root document nodes.
   1.976 +  if (aElement != mDocument->GetRootElement()) {
   1.977 +    return;
   1.978 +  }
   1.979 +
   1.980 +  // Don't bother processing offline manifest for documents
   1.981 +  // without a docshell
   1.982 +  if (!mDocShell) {
   1.983 +    return;
   1.984 +  }
   1.985 +
   1.986 +  // Check for a manifest= attribute.
   1.987 +  nsAutoString manifestSpec;
   1.988 +  aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
   1.989 +  ProcessOfflineManifest(manifestSpec);
   1.990 +}
   1.991 +
   1.992 +void
   1.993 +nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
   1.994 +{
   1.995 +  // Don't bother processing offline manifest for documents
   1.996 +  // without a docshell
   1.997 +  if (!mDocShell) {
   1.998 +    return;
   1.999 +  }
  1.1000 +
  1.1001 +  // If the docshell's in private browsing mode, we don't want to do any
  1.1002 +  // manifest processing.
  1.1003 +  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);
  1.1004 +  if (loadContext->UsePrivateBrowsing()) {
  1.1005 +    return;
  1.1006 +  }
  1.1007 +
  1.1008 +  nsresult rv;
  1.1009 +
  1.1010 +  // Grab the application cache the document was loaded from, if any.
  1.1011 +  nsCOMPtr<nsIApplicationCache> applicationCache;
  1.1012 +
  1.1013 +  nsCOMPtr<nsIApplicationCacheChannel> applicationCacheChannel =
  1.1014 +    do_QueryInterface(mDocument->GetChannel());
  1.1015 +  if (applicationCacheChannel) {
  1.1016 +    bool loadedFromApplicationCache;
  1.1017 +    rv = applicationCacheChannel->GetLoadedFromApplicationCache(
  1.1018 +      &loadedFromApplicationCache);
  1.1019 +    if (NS_FAILED(rv)) {
  1.1020 +      return;
  1.1021 +    }
  1.1022 +
  1.1023 +    if (loadedFromApplicationCache) {
  1.1024 +      rv = applicationCacheChannel->GetApplicationCache(
  1.1025 +        getter_AddRefs(applicationCache));
  1.1026 +      if (NS_FAILED(rv)) {
  1.1027 +        return;
  1.1028 +      }
  1.1029 +    }
  1.1030 +  }
  1.1031 +
  1.1032 +  if (aManifestSpec.IsEmpty() && !applicationCache) {
  1.1033 +    // Not loaded from an application cache, and no manifest
  1.1034 +    // attribute.  Nothing to do here.
  1.1035 +    return;
  1.1036 +  }
  1.1037 +
  1.1038 +  CacheSelectionAction action = CACHE_SELECTION_NONE;
  1.1039 +  nsCOMPtr<nsIURI> manifestURI;
  1.1040 +
  1.1041 +  if (aManifestSpec.IsEmpty()) {
  1.1042 +    action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
  1.1043 +  }
  1.1044 +  else {
  1.1045 +    nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
  1.1046 +                                              aManifestSpec, mDocument,
  1.1047 +                                              mDocumentURI);
  1.1048 +    if (!manifestURI) {
  1.1049 +      return;
  1.1050 +    }
  1.1051 +
  1.1052 +    // Documents must list a manifest from the same origin
  1.1053 +    rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true, false);
  1.1054 +    if (NS_FAILED(rv)) {
  1.1055 +      action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
  1.1056 +    }
  1.1057 +    else {
  1.1058 +      // Only continue if the document has permission to use offline APIs or
  1.1059 +      // when preferences indicate to permit it automatically.
  1.1060 +      if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) &&
  1.1061 +          !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) &&
  1.1062 +          !nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
  1.1063 +        return;
  1.1064 +      }
  1.1065 +
  1.1066 +      bool fetchedWithHTTPGetOrEquiv = false;
  1.1067 +      nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mDocument->GetChannel()));
  1.1068 +      if (httpChannel) {
  1.1069 +        nsAutoCString method;
  1.1070 +        rv = httpChannel->GetRequestMethod(method);
  1.1071 +        if (NS_SUCCEEDED(rv))
  1.1072 +          fetchedWithHTTPGetOrEquiv = method.Equals("GET");
  1.1073 +      }
  1.1074 +
  1.1075 +      rv = SelectDocAppCache(applicationCache, manifestURI,
  1.1076 +                             fetchedWithHTTPGetOrEquiv, &action);
  1.1077 +      if (NS_FAILED(rv)) {
  1.1078 +        return;
  1.1079 +      }
  1.1080 +    }
  1.1081 +  }
  1.1082 +
  1.1083 +  if (action == CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST) {
  1.1084 +    rv = SelectDocAppCacheNoManifest(applicationCache,
  1.1085 +                                     getter_AddRefs(manifestURI),
  1.1086 +                                     &action);
  1.1087 +    if (NS_FAILED(rv)) {
  1.1088 +      return;
  1.1089 +    }
  1.1090 +  }
  1.1091 +
  1.1092 +  switch (action)
  1.1093 +  {
  1.1094 +  case CACHE_SELECTION_NONE:
  1.1095 +    break;
  1.1096 +  case CACHE_SELECTION_UPDATE: {
  1.1097 +    nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
  1.1098 +      do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
  1.1099 +
  1.1100 +    if (updateService) {
  1.1101 +      nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(mDocument);
  1.1102 +      updateService->ScheduleOnDocumentStop(manifestURI, mDocumentURI, domdoc);
  1.1103 +    }
  1.1104 +    break;
  1.1105 +  }
  1.1106 +  case CACHE_SELECTION_RELOAD: {
  1.1107 +    // This situation occurs only for toplevel documents, see bottom
  1.1108 +    // of SelectDocAppCache method.
  1.1109 +    // The document has been loaded from a different offline cache group than
  1.1110 +    // the manifest it refers to, i.e. this is a foreign entry, mark it as such 
  1.1111 +    // and force a reload to avoid loading it.  The next attempt will not 
  1.1112 +    // choose it.
  1.1113 +
  1.1114 +    applicationCacheChannel->MarkOfflineCacheEntryAsForeign();
  1.1115 +
  1.1116 +    nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
  1.1117 +
  1.1118 +    webNav->Stop(nsIWebNavigation::STOP_ALL);
  1.1119 +    webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
  1.1120 +    break;
  1.1121 +  }
  1.1122 +  default:
  1.1123 +    NS_ASSERTION(false,
  1.1124 +          "Cache selection algorithm didn't decide on proper action");
  1.1125 +    break;
  1.1126 +  }
  1.1127 +}
  1.1128 +
  1.1129 +void
  1.1130 +nsContentSink::ScrollToRef()
  1.1131 +{
  1.1132 +  mDocument->ScrollToRef();
  1.1133 +}
  1.1134 +
  1.1135 +void
  1.1136 +nsContentSink::StartLayout(bool aIgnorePendingSheets)
  1.1137 +{
  1.1138 +  if (mLayoutStarted) {
  1.1139 +    // Nothing to do here
  1.1140 +    return;
  1.1141 +  }
  1.1142 +  
  1.1143 +  mDeferredLayoutStart = true;
  1.1144 +
  1.1145 +  if (!aIgnorePendingSheets && WaitForPendingSheets()) {
  1.1146 +    // Bail out; we'll start layout when the sheets load
  1.1147 +    return;
  1.1148 +  }
  1.1149 +
  1.1150 +  mDeferredLayoutStart = false;
  1.1151 +
  1.1152 +  // Notify on all our content.  If none of our presshells have started layout
  1.1153 +  // yet it'll be a no-op except for updating our data structures, a la
  1.1154 +  // UpdateChildCounts() (because we don't want to double-notify on whatever we
  1.1155 +  // have right now).  If some of them _have_ started layout, we want to make
  1.1156 +  // sure to flush tags instead of just calling UpdateChildCounts() after we
  1.1157 +  // loop over the shells.
  1.1158 +  FlushTags();
  1.1159 +
  1.1160 +  mLayoutStarted = true;
  1.1161 +  mLastNotificationTime = PR_Now();
  1.1162 +
  1.1163 +  mDocument->SetMayStartLayout(true);
  1.1164 +  nsCOMPtr<nsIPresShell> shell = mDocument->GetShell();
  1.1165 +  // Make sure we don't call Initialize() for a shell that has
  1.1166 +  // already called it. This can happen when the layout frame for
  1.1167 +  // an iframe is constructed *between* the Embed() call for the
  1.1168 +  // docshell in the iframe, and the content sink's call to OpenBody().
  1.1169 +  // (Bug 153815)
  1.1170 +  if (shell && !shell->DidInitialize()) {
  1.1171 +    nsRect r = shell->GetPresContext()->GetVisibleArea();
  1.1172 +    nsCOMPtr<nsIPresShell> shellGrip = shell;
  1.1173 +    nsresult rv = shell->Initialize(r.width, r.height);
  1.1174 +    if (NS_FAILED(rv)) {
  1.1175 +      return;
  1.1176 +    }
  1.1177 +  }
  1.1178 +
  1.1179 +  // If the document we are loading has a reference or it is a
  1.1180 +  // frameset document, disable the scroll bars on the views.
  1.1181 +
  1.1182 +  mDocument->SetScrollToRef(mDocumentURI);
  1.1183 +}
  1.1184 +
  1.1185 +void
  1.1186 +nsContentSink::NotifyAppend(nsIContent* aContainer, uint32_t aStartIndex)
  1.1187 +{
  1.1188 +  if (aContainer->GetCurrentDoc() != mDocument) {
  1.1189 +    // aContainer is not actually in our document anymore.... Just bail out of
  1.1190 +    // here; notifying on our document for this append would be wrong.
  1.1191 +    return;
  1.1192 +  }
  1.1193 +
  1.1194 +  mInNotification++;
  1.1195 +  
  1.1196 +  {
  1.1197 +    // Scope so we call EndUpdate before we decrease mInNotification
  1.1198 +    MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
  1.1199 +    nsNodeUtils::ContentAppended(aContainer,
  1.1200 +                                 aContainer->GetChildAt(aStartIndex),
  1.1201 +                                 aStartIndex);
  1.1202 +    mLastNotificationTime = PR_Now();
  1.1203 +  }
  1.1204 +
  1.1205 +  mInNotification--;
  1.1206 +}
  1.1207 +
  1.1208 +NS_IMETHODIMP
  1.1209 +nsContentSink::Notify(nsITimer *timer)
  1.1210 +{
  1.1211 +  if (mParsing) {
  1.1212 +    // We shouldn't interfere with our normal DidProcessAToken logic
  1.1213 +    mDroppedTimer = true;
  1.1214 +    return NS_OK;
  1.1215 +  }
  1.1216 +  
  1.1217 +  if (WaitForPendingSheets()) {
  1.1218 +    mDeferredFlushTags = true;
  1.1219 +  } else {
  1.1220 +    FlushTags();
  1.1221 +
  1.1222 +    // Now try and scroll to the reference
  1.1223 +    // XXX Should we scroll unconditionally for history loads??
  1.1224 +    ScrollToRef();
  1.1225 +  }
  1.1226 +
  1.1227 +  mNotificationTimer = nullptr;
  1.1228 +  return NS_OK;
  1.1229 +}
  1.1230 +
  1.1231 +bool
  1.1232 +nsContentSink::IsTimeToNotify()
  1.1233 +{
  1.1234 +  if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
  1.1235 +      mInMonolithicContainer) {
  1.1236 +    return false;
  1.1237 +  }
  1.1238 +
  1.1239 +  if (WaitForPendingSheets()) {
  1.1240 +    mDeferredFlushTags = true;
  1.1241 +    return false;
  1.1242 +  }
  1.1243 +
  1.1244 +  PRTime now = PR_Now();
  1.1245 +
  1.1246 +  int64_t interval = GetNotificationInterval();
  1.1247 +  int64_t diff = now - mLastNotificationTime;
  1.1248 +
  1.1249 +  if (diff > interval) {
  1.1250 +    mBackoffCount--;
  1.1251 +    return true;
  1.1252 +  }
  1.1253 +
  1.1254 +  return false;
  1.1255 +}
  1.1256 +
  1.1257 +nsresult
  1.1258 +nsContentSink::WillInterruptImpl()
  1.1259 +{
  1.1260 +  nsresult result = NS_OK;
  1.1261 +
  1.1262 +  SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
  1.1263 +             ("nsContentSink::WillInterrupt: this=%p", this));
  1.1264 +#ifndef SINK_NO_INCREMENTAL
  1.1265 +  if (WaitForPendingSheets()) {
  1.1266 +    mDeferredFlushTags = true;
  1.1267 +  } else if (sNotifyOnTimer && mLayoutStarted) {
  1.1268 +    if (mBackoffCount && !mInMonolithicContainer) {
  1.1269 +      int64_t now = PR_Now();
  1.1270 +      int64_t interval = GetNotificationInterval();
  1.1271 +      int64_t diff = now - mLastNotificationTime;
  1.1272 +
  1.1273 +      // If it's already time for us to have a notification
  1.1274 +      if (diff > interval || mDroppedTimer) {
  1.1275 +        mBackoffCount--;
  1.1276 +        SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1.1277 +                   ("nsContentSink::WillInterrupt: flushing tags since we've "
  1.1278 +                    "run out time; backoff count: %d", mBackoffCount));
  1.1279 +        result = FlushTags();
  1.1280 +        if (mDroppedTimer) {
  1.1281 +          ScrollToRef();
  1.1282 +          mDroppedTimer = false;
  1.1283 +        }
  1.1284 +      } else if (!mNotificationTimer) {
  1.1285 +        interval -= diff;
  1.1286 +        int32_t delay = interval;
  1.1287 +
  1.1288 +        // Convert to milliseconds
  1.1289 +        delay /= PR_USEC_PER_MSEC;
  1.1290 +
  1.1291 +        mNotificationTimer = do_CreateInstance("@mozilla.org/timer;1",
  1.1292 +                                               &result);
  1.1293 +        if (NS_SUCCEEDED(result)) {
  1.1294 +          SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1.1295 +                     ("nsContentSink::WillInterrupt: setting up timer with "
  1.1296 +                      "delay %d", delay));
  1.1297 +
  1.1298 +          result =
  1.1299 +            mNotificationTimer->InitWithCallback(this, delay,
  1.1300 +                                                 nsITimer::TYPE_ONE_SHOT);
  1.1301 +          if (NS_FAILED(result)) {
  1.1302 +            mNotificationTimer = nullptr;
  1.1303 +          }
  1.1304 +        }
  1.1305 +      }
  1.1306 +    }
  1.1307 +  } else {
  1.1308 +    SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1.1309 +               ("nsContentSink::WillInterrupt: flushing tags "
  1.1310 +                "unconditionally"));
  1.1311 +    result = FlushTags();
  1.1312 +  }
  1.1313 +#endif
  1.1314 +
  1.1315 +  mParsing = false;
  1.1316 +
  1.1317 +  return result;
  1.1318 +}
  1.1319 +
  1.1320 +nsresult
  1.1321 +nsContentSink::WillResumeImpl()
  1.1322 +{
  1.1323 +  SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
  1.1324 +             ("nsContentSink::WillResume: this=%p", this));
  1.1325 +
  1.1326 +  mParsing = true;
  1.1327 +
  1.1328 +  return NS_OK;
  1.1329 +}
  1.1330 +
  1.1331 +nsresult
  1.1332 +nsContentSink::DidProcessATokenImpl()
  1.1333 +{
  1.1334 +  if (mRunsToCompletion || !mParser) {
  1.1335 +    return NS_OK;
  1.1336 +  }
  1.1337 +
  1.1338 +  // Get the current user event time
  1.1339 +  nsIPresShell *shell = mDocument->GetShell();
  1.1340 +  if (!shell) {
  1.1341 +    // If there's no pres shell in the document, return early since
  1.1342 +    // we're not laying anything out here.
  1.1343 +    return NS_OK;
  1.1344 +  }
  1.1345 +
  1.1346 +  // Increase before comparing to gEventProbeRate
  1.1347 +  ++mDeflectedCount;
  1.1348 +
  1.1349 +  // Check if there's a pending event
  1.1350 +  if (sPendingEventMode != 0 && !mHasPendingEvent &&
  1.1351 +      (mDeflectedCount % sEventProbeRate) == 0) {
  1.1352 +    nsViewManager* vm = shell->GetViewManager();
  1.1353 +    NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
  1.1354 +    nsCOMPtr<nsIWidget> widget;
  1.1355 +    vm->GetRootWidget(getter_AddRefs(widget));
  1.1356 +    mHasPendingEvent = widget && widget->HasPendingInputEvent();
  1.1357 +  }
  1.1358 +
  1.1359 +  if (mHasPendingEvent && sPendingEventMode == 2) {
  1.1360 +    return NS_ERROR_HTMLPARSER_INTERRUPTED;
  1.1361 +  }
  1.1362 +
  1.1363 +  // Have we processed enough tokens to check time?
  1.1364 +  if (!mHasPendingEvent &&
  1.1365 +      mDeflectedCount < uint32_t(mDynamicLowerValue ? sInteractiveDeflectCount :
  1.1366 +                                                      sPerfDeflectCount)) {
  1.1367 +    return NS_OK;
  1.1368 +  }
  1.1369 +
  1.1370 +  mDeflectedCount = 0;
  1.1371 +
  1.1372 +  // Check if it's time to return to the main event loop
  1.1373 +  if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
  1.1374 +    return NS_ERROR_HTMLPARSER_INTERRUPTED;
  1.1375 +  }
  1.1376 +
  1.1377 +  return NS_OK;
  1.1378 +}
  1.1379 +
  1.1380 +//----------------------------------------------------------------------
  1.1381 +
  1.1382 +void
  1.1383 +nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
  1.1384 +{
  1.1385 +  static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
  1.1386 +  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
  1.1387 +  if (appShell)
  1.1388 +    appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
  1.1389 +}
  1.1390 +
  1.1391 +void
  1.1392 +nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
  1.1393 +{
  1.1394 +  // Remember nested updates from updates that we started.
  1.1395 +  if (mInNotification > 0 && mUpdatesInNotification < 2) {
  1.1396 +    ++mUpdatesInNotification;
  1.1397 +  }
  1.1398 +
  1.1399 +  // If we're in a script and we didn't do the notification,
  1.1400 +  // something else in the script processing caused the
  1.1401 +  // notification to occur. Since this could result in frame
  1.1402 +  // creation, make sure we've flushed everything before we
  1.1403 +  // continue.
  1.1404 +
  1.1405 +  if (!mInNotification++) {
  1.1406 +    FlushTags();
  1.1407 +  }
  1.1408 +}
  1.1409 +
  1.1410 +void
  1.1411 +nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
  1.1412 +{
  1.1413 +  // If we're in a script and we didn't do the notification,
  1.1414 +  // something else in the script processing caused the
  1.1415 +  // notification to occur. Update our notion of how much
  1.1416 +  // has been flushed to include any new content if ending
  1.1417 +  // this update leaves us not inside a notification.
  1.1418 +  if (!--mInNotification) {
  1.1419 +    UpdateChildCounts();
  1.1420 +  }
  1.1421 +}
  1.1422 +
  1.1423 +void
  1.1424 +nsContentSink::DidBuildModelImpl(bool aTerminated)
  1.1425 +{
  1.1426 +  if (mDocument) {
  1.1427 +    MOZ_ASSERT(aTerminated ||
  1.1428 +               mDocument->GetReadyStateEnum() ==
  1.1429 +               nsIDocument::READYSTATE_LOADING, "Bad readyState");
  1.1430 +    mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
  1.1431 +  }
  1.1432 +
  1.1433 +  if (mScriptLoader) {
  1.1434 +    mScriptLoader->ParsingComplete(aTerminated);
  1.1435 +  }
  1.1436 +
  1.1437 +  if (!mDocument->HaveFiredDOMTitleChange()) {
  1.1438 +    mDocument->NotifyPossibleTitleChange(false);
  1.1439 +  }
  1.1440 +
  1.1441 +  // Cancel a timer if we had one out there
  1.1442 +  if (mNotificationTimer) {
  1.1443 +    SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1.1444 +               ("nsContentSink::DidBuildModel: canceling notification "
  1.1445 +                "timeout"));
  1.1446 +    mNotificationTimer->Cancel();
  1.1447 +    mNotificationTimer = 0;
  1.1448 +  }	
  1.1449 +}
  1.1450 +
  1.1451 +void
  1.1452 +nsContentSink::DropParserAndPerfHint(void)
  1.1453 +{
  1.1454 +  if (!mParser) {
  1.1455 +    // Make sure we don't unblock unload too many times
  1.1456 +    return;
  1.1457 +  }
  1.1458 +  
  1.1459 +  // Ref. Bug 49115
  1.1460 +  // Do this hack to make sure that the parser
  1.1461 +  // doesn't get destroyed, accidently, before
  1.1462 +  // the circularity, between sink & parser, is
  1.1463 +  // actually broken.
  1.1464 +  // Drop our reference to the parser to get rid of a circular
  1.1465 +  // reference.
  1.1466 +  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
  1.1467 +
  1.1468 +  if (mDynamicLowerValue) {
  1.1469 +    // Reset the performance hint which was set to FALSE
  1.1470 +    // when mDynamicLowerValue was set.
  1.1471 +    FavorPerformanceHint(true, 0);
  1.1472 +  }
  1.1473 +
  1.1474 +  if (!mRunsToCompletion) {
  1.1475 +    mDocument->UnblockOnload(true);
  1.1476 +  }
  1.1477 +}
  1.1478 +
  1.1479 +bool
  1.1480 +nsContentSink::IsScriptExecutingImpl()
  1.1481 +{
  1.1482 +  return !!mScriptLoader->GetCurrentScript();
  1.1483 +}
  1.1484 +
  1.1485 +nsresult
  1.1486 +nsContentSink::WillParseImpl(void)
  1.1487 +{
  1.1488 +  if (mRunsToCompletion || !mDocument) {
  1.1489 +    return NS_OK;
  1.1490 +  }
  1.1491 +
  1.1492 +  nsIPresShell *shell = mDocument->GetShell();
  1.1493 +  if (!shell) {
  1.1494 +    return NS_OK;
  1.1495 +  }
  1.1496 +
  1.1497 +  uint32_t currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  1.1498 +
  1.1499 +  if (sEnablePerfMode == 0) {
  1.1500 +    nsViewManager* vm = shell->GetViewManager();
  1.1501 +    NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
  1.1502 +    uint32_t lastEventTime;
  1.1503 +    vm->GetLastUserEventTime(lastEventTime);
  1.1504 +
  1.1505 +    bool newDynLower =
  1.1506 +      mDocument->IsInBackgroundWindow() ||
  1.1507 +      ((currentTime - mBeginLoadTime) > uint32_t(sInitialPerfTime) &&
  1.1508 +       (currentTime - lastEventTime) < uint32_t(sInteractiveTime));
  1.1509 +    
  1.1510 +    if (mDynamicLowerValue != newDynLower) {
  1.1511 +      FavorPerformanceHint(!newDynLower, 0);
  1.1512 +      mDynamicLowerValue = newDynLower;
  1.1513 +    }
  1.1514 +  }
  1.1515 +  
  1.1516 +  mDeflectedCount = 0;
  1.1517 +  mHasPendingEvent = false;
  1.1518 +
  1.1519 +  mCurrentParseEndTime = currentTime +
  1.1520 +    (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
  1.1521 +
  1.1522 +  return NS_OK;
  1.1523 +}
  1.1524 +
  1.1525 +void
  1.1526 +nsContentSink::WillBuildModelImpl()
  1.1527 +{
  1.1528 +  if (!mRunsToCompletion) {
  1.1529 +    mDocument->BlockOnload();
  1.1530 +
  1.1531 +    mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  1.1532 +  }
  1.1533 +
  1.1534 +  mDocument->ResetScrolledToRefAlready();
  1.1535 +
  1.1536 +  if (mProcessLinkHeaderEvent.get()) {
  1.1537 +    mProcessLinkHeaderEvent.Revoke();
  1.1538 +
  1.1539 +    DoProcessLinkHeader();
  1.1540 +  }
  1.1541 +}
  1.1542 +
  1.1543 +/* static */
  1.1544 +void
  1.1545 +nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
  1.1546 +{
  1.1547 +  nsCOMPtr<nsIObserverService> observerService =
  1.1548 +    mozilla::services::GetObserverService();
  1.1549 +  if (observerService) {
  1.1550 +    nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
  1.1551 +    observerService->
  1.1552 +      NotifyObservers(domDoc, "document-element-inserted",
  1.1553 +                      EmptyString().get());
  1.1554 +  }
  1.1555 +}

mercurial