content/base/src/nsContentSink.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     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 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * Base class for the XML and HTML content sinks, which construct a
     9  * DOM based on information from the parser.
    10  */
    12 #include "nsContentSink.h"
    13 #include "nsScriptLoader.h"
    14 #include "nsIDocument.h"
    15 #include "nsIDOMDocument.h"
    16 #include "mozilla/css/Loader.h"
    17 #include "nsStyleLinkElement.h"
    18 #include "nsIDocShell.h"
    19 #include "nsILoadContext.h"
    20 #include "nsCPrefetchService.h"
    21 #include "nsIURI.h"
    22 #include "nsNetUtil.h"
    23 #include "nsIHttpChannel.h"
    24 #include "nsIContent.h"
    25 #include "nsIPresShell.h"
    26 #include "nsPresContext.h"
    27 #include "nsViewManager.h"
    28 #include "nsIAtom.h"
    29 #include "nsGkAtoms.h"
    30 #include "nsNetCID.h"
    31 #include "nsIOfflineCacheUpdate.h"
    32 #include "nsIApplicationCache.h"
    33 #include "nsIApplicationCacheContainer.h"
    34 #include "nsIApplicationCacheChannel.h"
    35 #include "nsIScriptSecurityManager.h"
    36 #include "nsICookieService.h"
    37 #include "nsContentUtils.h"
    38 #include "nsNodeInfoManager.h"
    39 #include "nsIAppShell.h"
    40 #include "nsIWidget.h"
    41 #include "nsWidgetsCID.h"
    42 #include "nsIDOMNode.h"
    43 #include "mozAutoDocUpdate.h"
    44 #include "nsIWebNavigation.h"
    45 #include "nsGenericHTMLElement.h"
    46 #include "nsHTMLDNSPrefetch.h"
    47 #include "nsIObserverService.h"
    48 #include "mozilla/Preferences.h"
    49 #include "nsParserConstants.h"
    51 using namespace mozilla;
    53 PRLogModuleInfo* gContentSinkLogModuleInfo;
    55 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
    56 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
    58 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
    59   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
    60   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    61   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
    62   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
    63   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
    64   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
    65 NS_INTERFACE_MAP_END
    67 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
    69 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
    70   if (tmp->mDocument) {
    71     tmp->mDocument->RemoveObserver(tmp);
    72   }
    73   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
    74   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
    75   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
    76   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptLoader)
    77 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
    79   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
    80   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
    81   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
    82   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
    83 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    86 nsContentSink::nsContentSink()
    87 {
    88   // We have a zeroing operator new
    89   NS_ASSERTION(!mLayoutStarted, "What?");
    90   NS_ASSERTION(!mDynamicLowerValue, "What?");
    91   NS_ASSERTION(!mParsing, "What?");
    92   NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
    93   NS_ASSERTION(mDeflectedCount == 0, "What?");
    94   NS_ASSERTION(!mDroppedTimer, "What?");
    95   NS_ASSERTION(mInMonolithicContainer == 0, "What?");
    96   NS_ASSERTION(mInNotification == 0, "What?");
    97   NS_ASSERTION(!mDeferredLayoutStart, "What?");
    99 #ifdef DEBUG
   100   if (!gContentSinkLogModuleInfo) {
   101     gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink");
   102   }
   103 #endif
   104 }
   106 nsContentSink::~nsContentSink()
   107 {
   108   if (mDocument) {
   109     // Remove ourselves just to be safe, though we really should have
   110     // been removed in DidBuildModel if everything worked right.
   111     mDocument->RemoveObserver(this);
   112   }
   113 }
   115 bool    nsContentSink::sNotifyOnTimer;
   116 int32_t nsContentSink::sBackoffCount;
   117 int32_t nsContentSink::sNotificationInterval;
   118 int32_t nsContentSink::sInteractiveDeflectCount;
   119 int32_t nsContentSink::sPerfDeflectCount;
   120 int32_t nsContentSink::sPendingEventMode;
   121 int32_t nsContentSink::sEventProbeRate;
   122 int32_t nsContentSink::sInteractiveParseTime;
   123 int32_t nsContentSink::sPerfParseTime;
   124 int32_t nsContentSink::sInteractiveTime;
   125 int32_t nsContentSink::sInitialPerfTime;
   126 int32_t nsContentSink::sEnablePerfMode;
   128 void
   129 nsContentSink::InitializeStatics()
   130 {
   131   Preferences::AddBoolVarCache(&sNotifyOnTimer,
   132                                "content.notify.ontimer", true);
   133   // -1 means never.
   134   Preferences::AddIntVarCache(&sBackoffCount,
   135                               "content.notify.backoffcount", -1);
   136   // The gNotificationInterval has a dramatic effect on how long it
   137   // takes to initially display content for slow connections.
   138   // The current value provides good
   139   // incremental display of content without causing an increase
   140   // in page load time. If this value is set below 1/10 of second
   141   // it starts to impact page load performance.
   142   // see bugzilla bug 72138 for more info.
   143   Preferences::AddIntVarCache(&sNotificationInterval,
   144                               "content.notify.interval", 120000);
   145   Preferences::AddIntVarCache(&sInteractiveDeflectCount,
   146                               "content.sink.interactive_deflect_count", 0);
   147   Preferences::AddIntVarCache(&sPerfDeflectCount,
   148                               "content.sink.perf_deflect_count", 200);
   149   Preferences::AddIntVarCache(&sPendingEventMode,
   150                               "content.sink.pending_event_mode", 1);
   151   Preferences::AddIntVarCache(&sEventProbeRate,
   152                               "content.sink.event_probe_rate", 1);
   153   Preferences::AddIntVarCache(&sInteractiveParseTime,
   154                               "content.sink.interactive_parse_time", 3000);
   155   Preferences::AddIntVarCache(&sPerfParseTime,
   156                               "content.sink.perf_parse_time", 360000);
   157   Preferences::AddIntVarCache(&sInteractiveTime,
   158                               "content.sink.interactive_time", 750000);
   159   Preferences::AddIntVarCache(&sInitialPerfTime,
   160                               "content.sink.initial_perf_time", 2000000);
   161   Preferences::AddIntVarCache(&sEnablePerfMode,
   162                               "content.sink.enable_perf_mode", 0);
   163 }
   165 nsresult
   166 nsContentSink::Init(nsIDocument* aDoc,
   167                     nsIURI* aURI,
   168                     nsISupports* aContainer,
   169                     nsIChannel* aChannel)
   170 {
   171   NS_PRECONDITION(aDoc, "null ptr");
   172   NS_PRECONDITION(aURI, "null ptr");
   174   if (!aDoc || !aURI) {
   175     return NS_ERROR_NULL_POINTER;
   176   }
   178   mDocument = aDoc;
   180   mDocumentURI = aURI;
   181   mDocShell = do_QueryInterface(aContainer);
   182   mScriptLoader = mDocument->ScriptLoader();
   184   if (!mRunsToCompletion) {
   185     if (mDocShell) {
   186       uint32_t loadType = 0;
   187       mDocShell->GetLoadType(&loadType);
   188       mDocument->SetChangeScrollPosWhenScrollingToRef(
   189         (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
   190     }
   192     ProcessHTTPHeaders(aChannel);
   193   }
   195   mCSSLoader = aDoc->CSSLoader();
   197   mNodeInfoManager = aDoc->NodeInfoManager();
   199   mBackoffCount = sBackoffCount;
   201   if (sEnablePerfMode != 0) {
   202     mDynamicLowerValue = sEnablePerfMode == 1;
   203     FavorPerformanceHint(!mDynamicLowerValue, 0);
   204   }
   206   return NS_OK;
   207 }
   209 NS_IMETHODIMP
   210 nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
   211                                 bool aWasAlternate,
   212                                 nsresult aStatus)
   213 {
   214   NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
   215   if (!aWasAlternate) {
   216     NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
   217     --mPendingSheetCount;
   219     if (mPendingSheetCount == 0 &&
   220         (mDeferredLayoutStart || mDeferredFlushTags)) {
   221       if (mDeferredFlushTags) {
   222         FlushTags();
   223       }
   224       if (mDeferredLayoutStart) {
   225         // We might not have really started layout, since this sheet was still
   226         // loading.  Do it now.  Probably doesn't matter whether we do this
   227         // before or after we unblock scripts, but before feels saner.  Note
   228         // that if mDeferredLayoutStart is true, that means any subclass
   229         // StartLayout() stuff that needs to happen has already happened, so we
   230         // don't need to worry about it.
   231         StartLayout(false);
   232       }
   234       // Go ahead and try to scroll to our ref if we have one
   235       ScrollToRef();
   236     }
   238     mScriptLoader->RemoveExecuteBlocker();
   239   }
   241   return NS_OK;
   242 }
   244 nsresult
   245 nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
   246 {
   247   nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
   249   if (!httpchannel) {
   250     return NS_OK;
   251   }
   253   // Note that the only header we care about is the "link" header, since we
   254   // have all the infrastructure for kicking off stylesheet loads.
   256   nsAutoCString linkHeader;
   258   nsresult rv = httpchannel->GetResponseHeader(NS_LITERAL_CSTRING("link"),
   259                                                linkHeader);
   260   if (NS_SUCCEEDED(rv) && !linkHeader.IsEmpty()) {
   261     mDocument->SetHeaderData(nsGkAtoms::link,
   262                              NS_ConvertASCIItoUTF16(linkHeader));
   264     NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
   265                  "Already dispatched an event?");
   267     mProcessLinkHeaderEvent =
   268       NS_NewNonOwningRunnableMethod(this,
   269         &nsContentSink::DoProcessLinkHeader);
   270     rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get());
   271     if (NS_FAILED(rv)) {
   272       mProcessLinkHeaderEvent.Forget();
   273     }
   274   }
   276   return NS_OK;
   277 }
   279 nsresult
   280 nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
   281                                  nsIContent* aContent)
   282 {
   283   nsresult rv = NS_OK;
   284   // necko doesn't process headers coming in from the parser
   286   mDocument->SetHeaderData(aHeader, aValue);
   288   if (aHeader == nsGkAtoms::setcookie) {
   289     // Note: Necko already handles cookies set via the channel.  We can't just
   290     // call SetCookie on the channel because we want to do some security checks
   291     // here.
   292     nsCOMPtr<nsICookieService> cookieServ =
   293       do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv);
   294     if (NS_FAILED(rv)) {
   295       return rv;
   296     }
   298     // Get a URI from the document principal
   300     // We use the original codebase in case the codebase was changed
   301     // by SetDomain
   303     // Note that a non-codebase principal (eg the system principal) will return
   304     // a null URI.
   305     nsCOMPtr<nsIURI> codebaseURI;
   306     rv = mDocument->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
   307     NS_ENSURE_TRUE(codebaseURI, rv);
   309     nsCOMPtr<nsIChannel> channel;
   310     if (mParser) {
   311       mParser->GetChannel(getter_AddRefs(channel));
   312     }
   314     rv = cookieServ->SetCookieString(codebaseURI,
   315                                      nullptr,
   316                                      NS_ConvertUTF16toUTF8(aValue).get(),
   317                                      channel);
   318     if (NS_FAILED(rv)) {
   319       return rv;
   320     }
   321   }
   322   else if (aHeader == nsGkAtoms::msthemecompatible) {
   323     // Disable theming for the presshell if the value is no.
   324     // XXXbz don't we want to support this as an HTTP header too?
   325     nsAutoString value(aValue);
   326     if (value.LowerCaseEqualsLiteral("no")) {
   327       nsIPresShell* shell = mDocument->GetShell();
   328       if (shell) {
   329         shell->DisableThemeSupport();
   330       }
   331     }
   332   }
   334   return rv;
   335 }
   338 void
   339 nsContentSink::DoProcessLinkHeader()
   340 {
   341   nsAutoString value;
   342   mDocument->GetHeaderData(nsGkAtoms::link, value);
   343   ProcessLinkHeader(value);
   344 }
   346 // check whether the Link header field applies to the context resource
   347 // see <http://tools.ietf.org/html/rfc5988#section-5.2>
   349 bool
   350 nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
   351 {
   352   if (aAnchor.IsEmpty()) {
   353     // anchor parameter not present or empty -> same document reference
   354     return true;
   355   }
   357   nsIURI* docUri = mDocument->GetDocumentURI();
   359   // the document URI might contain a fragment identifier ("#...')
   360   // we want to ignore that because it's invisible to the server
   361   // and just affects the local interpretation in the recipient
   362   nsCOMPtr<nsIURI> contextUri;
   363   nsresult rv = docUri->CloneIgnoringRef(getter_AddRefs(contextUri));
   365   if (NS_FAILED(rv)) {
   366     // copying failed
   367     return false;
   368   }
   370   // resolve anchor against context    
   371   nsCOMPtr<nsIURI> resolvedUri;
   372   rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor,
   373       nullptr, contextUri);
   375   if (NS_FAILED(rv)) {
   376     // resolving failed
   377     return false;
   378   }
   380   bool same;
   381   rv = contextUri->Equals(resolvedUri, &same); 
   382   if (NS_FAILED(rv)) {
   383     // comparison failed
   384     return false;
   385   }
   387   return same;
   388 }
   390 // Decode a parameter value using the encoding defined in RFC 5987 (in place)
   391 //
   392 //   charset  "'" [ language ] "'" value-chars
   393 //
   394 // returns true when decoding happened successfully (otherwise leaves
   395 // passed value alone)
   396 bool
   397 nsContentSink::Decode5987Format(nsAString& aEncoded) {
   399   nsresult rv;
   400   nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
   401   do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
   402   if (NS_FAILED(rv))
   403     return false;
   405   nsAutoCString asciiValue;
   407   const char16_t* encstart = aEncoded.BeginReading();
   408   const char16_t* encend = aEncoded.EndReading();
   410   // create a plain ASCII string, aborting if we can't do that
   411   // converted form is always shorter than input
   412   while (encstart != encend) {
   413     if (*encstart > 0 && *encstart < 128) {
   414       asciiValue.Append((char)*encstart);
   415     } else {
   416       return false;
   417     }
   418     encstart++;
   419   }
   421   nsAutoString decoded;
   422   nsAutoCString language;
   424   rv = mimehdrpar->DecodeRFC5987Param(asciiValue, language, decoded);
   425   if (NS_FAILED(rv))
   426     return false;
   428   aEncoded = decoded;
   429   return true;
   430 }
   432 nsresult
   433 nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
   434 {
   435   nsresult rv = NS_OK;
   437   // keep track where we are within the header field
   438   bool seenParameters = false;
   440   // parse link content and call process style link
   441   nsAutoString href;
   442   nsAutoString rel;
   443   nsAutoString title;
   444   nsAutoString titleStar;
   445   nsAutoString type;
   446   nsAutoString media;
   447   nsAutoString anchor;
   449   // copy to work buffer
   450   nsAutoString stringList(aLinkData);
   452   // put an extra null at the end
   453   stringList.Append(kNullCh);
   455   char16_t* start = stringList.BeginWriting();
   456   char16_t* end   = start;
   457   char16_t* last  = start;
   458   char16_t  endCh;
   460   while (*start != kNullCh) {
   461     // skip leading space
   462     while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) {
   463       ++start;
   464     }
   466     end = start;
   467     last = end - 1;
   469     bool wasQuotedString = false;
   471     // look for semicolon or comma
   472     while (*end != kNullCh && *end != kSemicolon && *end != kComma) {
   473       char16_t ch = *end;
   475       if (ch == kQuote || ch == kLessThan) {
   476         // quoted string
   478         char16_t quote = ch;
   479         if (quote == kLessThan) {
   480           quote = kGreaterThan;
   481         }
   483         wasQuotedString = (ch == kQuote);
   485         char16_t* closeQuote = (end + 1);
   487         // seek closing quote
   488         while (*closeQuote != kNullCh && quote != *closeQuote) {
   489           // in quoted-string, "\" is an escape character
   490           if (wasQuotedString && *closeQuote == kBackSlash && *(closeQuote + 1) != kNullCh) {
   491             ++closeQuote;
   492           }
   494           ++closeQuote;
   495         }
   497         if (quote == *closeQuote) {
   498           // found closer
   500           // skip to close quote
   501           end = closeQuote;
   503           last = end - 1;
   505           ch = *(end + 1);
   507           if (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   508             // end string here
   509             *(++end) = kNullCh;
   511             ch = *(end + 1);
   513             // keep going until semi or comma
   514             while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   515               ++end;
   517               ch = *end;
   518             }
   519           }
   520         }
   521       }
   523       ++end;
   524       ++last;
   525     }
   527     endCh = *end;
   529     // end string here
   530     *end = kNullCh;
   532     if (start < end) {
   533       if ((*start == kLessThan) && (*last == kGreaterThan)) {
   534         *last = kNullCh;
   536         // first instance of <...> wins
   537         // also, do not allow hrefs after the first param was seen
   538         if (href.IsEmpty() && !seenParameters) {
   539           href = (start + 1);
   540           href.StripWhitespace();
   541         }
   542       } else {
   543         char16_t* equals = start;
   544         seenParameters = true;
   546         while ((*equals != kNullCh) && (*equals != kEqual)) {
   547           equals++;
   548         }
   550         if (*equals != kNullCh) {
   551           *equals = kNullCh;
   552           nsAutoString  attr(start);
   553           attr.StripWhitespace();
   555           char16_t* value = ++equals;
   556           while (nsCRT::IsAsciiSpace(*value)) {
   557             value++;
   558           }
   560           if ((*value == kQuote) && (*value == *last)) {
   561             *last = kNullCh;
   562             value++;
   563           }
   565           if (wasQuotedString) {
   566             // unescape in-place
   567             char16_t* unescaped = value;
   568             char16_t *src = value;
   570             while (*src != kNullCh) {
   571               if (*src == kBackSlash && *(src + 1) != kNullCh) {
   572                 src++;
   573               }
   574               *unescaped++ = *src++;
   575             }
   577             *unescaped = kNullCh;
   578           }
   580           if (attr.LowerCaseEqualsLiteral("rel")) {
   581             if (rel.IsEmpty()) {
   582               rel = value;
   583               rel.CompressWhitespace();
   584             }
   585           } else if (attr.LowerCaseEqualsLiteral("title")) {
   586             if (title.IsEmpty()) {
   587               title = value;
   588               title.CompressWhitespace();
   589             }
   590           } else if (attr.LowerCaseEqualsLiteral("title*")) {
   591             if (titleStar.IsEmpty() && !wasQuotedString) {
   592               // RFC 5987 encoding; uses token format only, so skip if we get
   593               // here with a quoted-string
   594               nsAutoString tmp;
   595               tmp = value;
   596               if (Decode5987Format(tmp)) {
   597                 titleStar = tmp;
   598                 titleStar.CompressWhitespace();
   599               } else {
   600                 // header value did not parse, throw it away
   601                 titleStar.Truncate();
   602               }
   603             }
   604           } else if (attr.LowerCaseEqualsLiteral("type")) {
   605             if (type.IsEmpty()) {
   606               type = value;
   607               type.StripWhitespace();
   608             }
   609           } else if (attr.LowerCaseEqualsLiteral("media")) {
   610             if (media.IsEmpty()) {
   611               media = value;
   613               // The HTML5 spec is formulated in terms of the CSS3 spec,
   614               // which specifies that media queries are case insensitive.
   615               nsContentUtils::ASCIIToLower(media);
   616             }
   617           } else if (attr.LowerCaseEqualsLiteral("anchor")) {
   618             if (anchor.IsEmpty()) {
   619               anchor = value;
   620               anchor.StripWhitespace();
   621             }
   622           }
   623         }
   624       }
   625     }
   627     if (endCh == kComma) {
   628       // hit a comma, process what we've got so far
   630       href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   631       if (!href.IsEmpty() && !rel.IsEmpty()) {
   632         rv = ProcessLink(anchor, href, rel,
   633                          // prefer RFC 5987 variant over non-I18zed version
   634                          titleStar.IsEmpty() ? title : titleStar,
   635                          type, media);
   636       }
   638       href.Truncate();
   639       rel.Truncate();
   640       title.Truncate();
   641       type.Truncate();
   642       media.Truncate();
   643       anchor.Truncate();
   645       seenParameters = false;
   646     }
   648     start = ++end;
   649   }
   651   href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   652   if (!href.IsEmpty() && !rel.IsEmpty()) {
   653     rv = ProcessLink(anchor, href, rel,
   654                      // prefer RFC 5987 variant over non-I18zed version
   655                      titleStar.IsEmpty() ? title : titleStar,
   656                      type, media);
   657   }
   659   return rv;
   660 }
   663 nsresult
   664 nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
   665                            const nsSubstring& aRel, const nsSubstring& aTitle,
   666                            const nsSubstring& aType, const nsSubstring& aMedia)
   667 {
   668   uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel);
   670   // The link relation may apply to a different resource, specified
   671   // in the anchor parameter. For the link relations supported so far,
   672   // we simply abort if the link applies to a resource different to the
   673   // one we've loaded
   674   if (!LinkContextIsOurDocument(aAnchor)) {
   675     return NS_OK;
   676   }
   678   bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
   679   // prefetch href if relation is "next" or "prefetch"
   680   if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
   681     PrefetchHref(aHref, mDocument, hasPrefetch);
   682   }
   684   if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::eDNS_PREFETCH)) {
   685     PrefetchDNS(aHref);
   686   }
   688   // is it a stylesheet link?
   689   if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
   690     return NS_OK;
   691   }
   693   bool isAlternate = linkTypes & nsStyleLinkElement::eALTERNATE;
   694   return ProcessStyleLink(nullptr, aHref, isAlternate, aTitle, aType,
   695                           aMedia);
   696 }
   698 nsresult
   699 nsContentSink::ProcessStyleLink(nsIContent* aElement,
   700                                 const nsSubstring& aHref,
   701                                 bool aAlternate,
   702                                 const nsSubstring& aTitle,
   703                                 const nsSubstring& aType,
   704                                 const nsSubstring& aMedia)
   705 {
   706   if (aAlternate && aTitle.IsEmpty()) {
   707     // alternates must have title return without error, for now
   708     return NS_OK;
   709   }
   711   nsAutoString  mimeType;
   712   nsAutoString  params;
   713   nsContentUtils::SplitMimeType(aType, mimeType, params);
   715   // see bug 18817
   716   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
   717     // Unknown stylesheet language
   718     return NS_OK;
   719   }
   721   nsCOMPtr<nsIURI> url;
   722   nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
   723                           mDocument->GetDocBaseURI());
   725   if (NS_FAILED(rv)) {
   726     // The URI is bad, move along, don't propagate the error (for now)
   727     return NS_OK;
   728   }
   730   NS_ASSERTION(!aElement ||
   731                aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
   732                "We only expect processing instructions here");
   734   // If this is a fragment parser, we don't want to observe.
   735   // We don't support CORS for processing instructions
   736   bool isAlternate;
   737   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
   738                                  CORS_NONE,
   739                                  mRunsToCompletion ? nullptr : this, &isAlternate);
   740   NS_ENSURE_SUCCESS(rv, rv);
   742   if (!isAlternate && !mRunsToCompletion) {
   743     ++mPendingSheetCount;
   744     mScriptLoader->AddExecuteBlocker();
   745   }
   747   return NS_OK;
   748 }
   751 nsresult
   752 nsContentSink::ProcessMETATag(nsIContent* aContent)
   753 {
   754   NS_ASSERTION(aContent, "missing meta-element");
   756   nsresult rv = NS_OK;
   758   // set any HTTP-EQUIV data into document's header data as well as url
   759   nsAutoString header;
   760   aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
   761   if (!header.IsEmpty()) {
   762     nsAutoString result;
   763     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
   764     if (!result.IsEmpty()) {
   765       nsContentUtils::ASCIIToLower(header);
   766       nsCOMPtr<nsIAtom> fieldAtom(do_GetAtom(header));
   767       rv = ProcessHeaderData(fieldAtom, result, aContent); 
   768     }
   769   }
   770   NS_ENSURE_SUCCESS(rv, rv);
   772   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
   773                             nsGkAtoms::handheldFriendly, eIgnoreCase)) {
   774     nsAutoString result;
   775     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
   776     if (!result.IsEmpty()) {
   777       nsContentUtils::ASCIIToLower(result);
   778       mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
   779     }
   780   }
   782   return rv;
   783 }
   786 void
   787 nsContentSink::PrefetchHref(const nsAString &aHref,
   788                             nsINode *aSource,
   789                             bool aExplicit)
   790 {
   791   //
   792   // SECURITY CHECK: disable prefetching from mailnews!
   793   //
   794   // walk up the docshell tree to see if any containing
   795   // docshell are of type MAIL.
   796   //
   797   if (!mDocShell)
   798     return;
   800   nsCOMPtr<nsIDocShell> docshell = mDocShell;
   802   nsCOMPtr<nsIDocShellTreeItem> parentItem;
   803   do {
   804     uint32_t appType = 0;
   805     nsresult rv = docshell->GetAppType(&appType);
   806     if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
   807       return; // do not prefetch from mailnews
   808     docshell->GetParent(getter_AddRefs(parentItem));
   809     if (parentItem) {
   810       docshell = do_QueryInterface(parentItem);
   811       if (!docshell) {
   812         NS_ERROR("cannot get a docshell from a treeItem!");
   813         return;
   814       }
   815     }
   816   } while (parentItem);
   818   // OK, we passed the security check...
   820   nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
   821   if (prefetchService) {
   822     // construct URI using document charset
   823     const nsACString &charset = mDocument->GetDocumentCharacterSet();
   824     nsCOMPtr<nsIURI> uri;
   825     NS_NewURI(getter_AddRefs(uri), aHref,
   826               charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
   827               mDocument->GetDocBaseURI());
   828     if (uri) {
   829       nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aSource);
   830       prefetchService->PrefetchURI(uri, mDocumentURI, domNode, aExplicit);
   831     }
   832   }
   833 }
   835 void
   836 nsContentSink::PrefetchDNS(const nsAString &aHref)
   837 {
   838   nsAutoString hostname;
   840   if (StringBeginsWith(aHref, NS_LITERAL_STRING("//")))  {
   841     hostname = Substring(aHref, 2);
   842   }
   843   else {
   844     nsCOMPtr<nsIURI> uri;
   845     NS_NewURI(getter_AddRefs(uri), aHref);
   846     if (!uri) {
   847       return;
   848     }
   849     nsAutoCString host;
   850     uri->GetHost(host);
   851     CopyUTF8toUTF16(host, hostname);
   852   }
   854   if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
   855     nsHTMLDNSPrefetch::PrefetchLow(hostname);
   856   }
   857 }
   859 nsresult
   860 nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
   861                                  nsIURI *aManifestURI,
   862                                  bool aFetchedWithHTTPGetOrEquiv,
   863                                  CacheSelectionAction *aAction)
   864 {
   865   nsresult rv;
   867   *aAction = CACHE_SELECTION_NONE;
   869   nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
   870     do_QueryInterface(mDocument);
   871   NS_ASSERTION(applicationCacheDocument,
   872                "mDocument must implement nsIApplicationCacheContainer.");
   874   if (aLoadApplicationCache) {
   875     nsCOMPtr<nsIURI> groupURI;
   876     rv = aLoadApplicationCache->GetManifestURI(getter_AddRefs(groupURI));
   877     NS_ENSURE_SUCCESS(rv, rv);
   879     bool equal = false;
   880     rv = groupURI->Equals(aManifestURI, &equal);
   881     NS_ENSURE_SUCCESS(rv, rv);
   883     if (!equal) {
   884       // This is a foreign entry, force a reload to avoid loading the foreign
   885       // entry. The entry will be marked as foreign to avoid loading it again.
   887       *aAction = CACHE_SELECTION_RELOAD;
   888     }
   889     else {
   890       // The http manifest attribute URI is equal to the manifest URI of
   891       // the cache the document was loaded from - associate the document with
   892       // that cache and invoke the cache update process.
   893 #ifdef DEBUG
   894       nsAutoCString docURISpec, clientID;
   895       mDocumentURI->GetAsciiSpec(docURISpec);
   896       aLoadApplicationCache->GetClientID(clientID);
   897       SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
   898           ("Selection: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
   899 #endif
   901       rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
   902       NS_ENSURE_SUCCESS(rv, rv);
   904       // Document will be added as implicit entry to the cache as part of
   905       // the update process.
   906       *aAction = CACHE_SELECTION_UPDATE;
   907     }
   908   }
   909   else {
   910     // The document was not loaded from an application cache
   911     // Here we know the manifest has the same origin as the
   912     // document. There is call to CheckMayLoad() on it above.
   914     if (!aFetchedWithHTTPGetOrEquiv) {
   915       // The document was not loaded using HTTP GET or equivalent
   916       // method. The spec says to run the cache selection algorithm w/o
   917       // the manifest specified.
   918       *aAction = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
   919     }
   920     else {
   921       // Always do an update in this case
   922       *aAction = CACHE_SELECTION_UPDATE;
   923     }
   924   }
   926   return NS_OK;
   927 }
   929 nsresult
   930 nsContentSink::SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
   931                                            nsIURI **aManifestURI,
   932                                            CacheSelectionAction *aAction)
   933 {
   934   *aManifestURI = nullptr;
   935   *aAction = CACHE_SELECTION_NONE;
   937   nsresult rv;
   939   if (aLoadApplicationCache) {
   940     // The document was loaded from an application cache, use that
   941     // application cache as the document's application cache.
   942     nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
   943       do_QueryInterface(mDocument);
   944     NS_ASSERTION(applicationCacheDocument,
   945                  "mDocument must implement nsIApplicationCacheContainer.");
   947 #ifdef DEBUG
   948     nsAutoCString docURISpec, clientID;
   949     mDocumentURI->GetAsciiSpec(docURISpec);
   950     aLoadApplicationCache->GetClientID(clientID);
   951     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
   952         ("Selection, no manifest: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
   953 #endif
   955     rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
   956     NS_ENSURE_SUCCESS(rv, rv);
   958     // Return the uri and invoke the update process for the selected
   959     // application cache.
   960     rv = aLoadApplicationCache->GetManifestURI(aManifestURI);
   961     NS_ENSURE_SUCCESS(rv, rv);
   963     *aAction = CACHE_SELECTION_UPDATE;
   964   }
   966   return NS_OK;
   967 }
   969 void
   970 nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
   971 {
   972   // Only check the manifest for root document nodes.
   973   if (aElement != mDocument->GetRootElement()) {
   974     return;
   975   }
   977   // Don't bother processing offline manifest for documents
   978   // without a docshell
   979   if (!mDocShell) {
   980     return;
   981   }
   983   // Check for a manifest= attribute.
   984   nsAutoString manifestSpec;
   985   aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
   986   ProcessOfflineManifest(manifestSpec);
   987 }
   989 void
   990 nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
   991 {
   992   // Don't bother processing offline manifest for documents
   993   // without a docshell
   994   if (!mDocShell) {
   995     return;
   996   }
   998   // If the docshell's in private browsing mode, we don't want to do any
   999   // manifest processing.
  1000   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);
  1001   if (loadContext->UsePrivateBrowsing()) {
  1002     return;
  1005   nsresult rv;
  1007   // Grab the application cache the document was loaded from, if any.
  1008   nsCOMPtr<nsIApplicationCache> applicationCache;
  1010   nsCOMPtr<nsIApplicationCacheChannel> applicationCacheChannel =
  1011     do_QueryInterface(mDocument->GetChannel());
  1012   if (applicationCacheChannel) {
  1013     bool loadedFromApplicationCache;
  1014     rv = applicationCacheChannel->GetLoadedFromApplicationCache(
  1015       &loadedFromApplicationCache);
  1016     if (NS_FAILED(rv)) {
  1017       return;
  1020     if (loadedFromApplicationCache) {
  1021       rv = applicationCacheChannel->GetApplicationCache(
  1022         getter_AddRefs(applicationCache));
  1023       if (NS_FAILED(rv)) {
  1024         return;
  1029   if (aManifestSpec.IsEmpty() && !applicationCache) {
  1030     // Not loaded from an application cache, and no manifest
  1031     // attribute.  Nothing to do here.
  1032     return;
  1035   CacheSelectionAction action = CACHE_SELECTION_NONE;
  1036   nsCOMPtr<nsIURI> manifestURI;
  1038   if (aManifestSpec.IsEmpty()) {
  1039     action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
  1041   else {
  1042     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
  1043                                               aManifestSpec, mDocument,
  1044                                               mDocumentURI);
  1045     if (!manifestURI) {
  1046       return;
  1049     // Documents must list a manifest from the same origin
  1050     rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true, false);
  1051     if (NS_FAILED(rv)) {
  1052       action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
  1054     else {
  1055       // Only continue if the document has permission to use offline APIs or
  1056       // when preferences indicate to permit it automatically.
  1057       if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) &&
  1058           !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) &&
  1059           !nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
  1060         return;
  1063       bool fetchedWithHTTPGetOrEquiv = false;
  1064       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mDocument->GetChannel()));
  1065       if (httpChannel) {
  1066         nsAutoCString method;
  1067         rv = httpChannel->GetRequestMethod(method);
  1068         if (NS_SUCCEEDED(rv))
  1069           fetchedWithHTTPGetOrEquiv = method.Equals("GET");
  1072       rv = SelectDocAppCache(applicationCache, manifestURI,
  1073                              fetchedWithHTTPGetOrEquiv, &action);
  1074       if (NS_FAILED(rv)) {
  1075         return;
  1080   if (action == CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST) {
  1081     rv = SelectDocAppCacheNoManifest(applicationCache,
  1082                                      getter_AddRefs(manifestURI),
  1083                                      &action);
  1084     if (NS_FAILED(rv)) {
  1085       return;
  1089   switch (action)
  1091   case CACHE_SELECTION_NONE:
  1092     break;
  1093   case CACHE_SELECTION_UPDATE: {
  1094     nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
  1095       do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
  1097     if (updateService) {
  1098       nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(mDocument);
  1099       updateService->ScheduleOnDocumentStop(manifestURI, mDocumentURI, domdoc);
  1101     break;
  1103   case CACHE_SELECTION_RELOAD: {
  1104     // This situation occurs only for toplevel documents, see bottom
  1105     // of SelectDocAppCache method.
  1106     // The document has been loaded from a different offline cache group than
  1107     // the manifest it refers to, i.e. this is a foreign entry, mark it as such 
  1108     // and force a reload to avoid loading it.  The next attempt will not 
  1109     // choose it.
  1111     applicationCacheChannel->MarkOfflineCacheEntryAsForeign();
  1113     nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
  1115     webNav->Stop(nsIWebNavigation::STOP_ALL);
  1116     webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
  1117     break;
  1119   default:
  1120     NS_ASSERTION(false,
  1121           "Cache selection algorithm didn't decide on proper action");
  1122     break;
  1126 void
  1127 nsContentSink::ScrollToRef()
  1129   mDocument->ScrollToRef();
  1132 void
  1133 nsContentSink::StartLayout(bool aIgnorePendingSheets)
  1135   if (mLayoutStarted) {
  1136     // Nothing to do here
  1137     return;
  1140   mDeferredLayoutStart = true;
  1142   if (!aIgnorePendingSheets && WaitForPendingSheets()) {
  1143     // Bail out; we'll start layout when the sheets load
  1144     return;
  1147   mDeferredLayoutStart = false;
  1149   // Notify on all our content.  If none of our presshells have started layout
  1150   // yet it'll be a no-op except for updating our data structures, a la
  1151   // UpdateChildCounts() (because we don't want to double-notify on whatever we
  1152   // have right now).  If some of them _have_ started layout, we want to make
  1153   // sure to flush tags instead of just calling UpdateChildCounts() after we
  1154   // loop over the shells.
  1155   FlushTags();
  1157   mLayoutStarted = true;
  1158   mLastNotificationTime = PR_Now();
  1160   mDocument->SetMayStartLayout(true);
  1161   nsCOMPtr<nsIPresShell> shell = mDocument->GetShell();
  1162   // Make sure we don't call Initialize() for a shell that has
  1163   // already called it. This can happen when the layout frame for
  1164   // an iframe is constructed *between* the Embed() call for the
  1165   // docshell in the iframe, and the content sink's call to OpenBody().
  1166   // (Bug 153815)
  1167   if (shell && !shell->DidInitialize()) {
  1168     nsRect r = shell->GetPresContext()->GetVisibleArea();
  1169     nsCOMPtr<nsIPresShell> shellGrip = shell;
  1170     nsresult rv = shell->Initialize(r.width, r.height);
  1171     if (NS_FAILED(rv)) {
  1172       return;
  1176   // If the document we are loading has a reference or it is a
  1177   // frameset document, disable the scroll bars on the views.
  1179   mDocument->SetScrollToRef(mDocumentURI);
  1182 void
  1183 nsContentSink::NotifyAppend(nsIContent* aContainer, uint32_t aStartIndex)
  1185   if (aContainer->GetCurrentDoc() != mDocument) {
  1186     // aContainer is not actually in our document anymore.... Just bail out of
  1187     // here; notifying on our document for this append would be wrong.
  1188     return;
  1191   mInNotification++;
  1194     // Scope so we call EndUpdate before we decrease mInNotification
  1195     MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
  1196     nsNodeUtils::ContentAppended(aContainer,
  1197                                  aContainer->GetChildAt(aStartIndex),
  1198                                  aStartIndex);
  1199     mLastNotificationTime = PR_Now();
  1202   mInNotification--;
  1205 NS_IMETHODIMP
  1206 nsContentSink::Notify(nsITimer *timer)
  1208   if (mParsing) {
  1209     // We shouldn't interfere with our normal DidProcessAToken logic
  1210     mDroppedTimer = true;
  1211     return NS_OK;
  1214   if (WaitForPendingSheets()) {
  1215     mDeferredFlushTags = true;
  1216   } else {
  1217     FlushTags();
  1219     // Now try and scroll to the reference
  1220     // XXX Should we scroll unconditionally for history loads??
  1221     ScrollToRef();
  1224   mNotificationTimer = nullptr;
  1225   return NS_OK;
  1228 bool
  1229 nsContentSink::IsTimeToNotify()
  1231   if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
  1232       mInMonolithicContainer) {
  1233     return false;
  1236   if (WaitForPendingSheets()) {
  1237     mDeferredFlushTags = true;
  1238     return false;
  1241   PRTime now = PR_Now();
  1243   int64_t interval = GetNotificationInterval();
  1244   int64_t diff = now - mLastNotificationTime;
  1246   if (diff > interval) {
  1247     mBackoffCount--;
  1248     return true;
  1251   return false;
  1254 nsresult
  1255 nsContentSink::WillInterruptImpl()
  1257   nsresult result = NS_OK;
  1259   SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
  1260              ("nsContentSink::WillInterrupt: this=%p", this));
  1261 #ifndef SINK_NO_INCREMENTAL
  1262   if (WaitForPendingSheets()) {
  1263     mDeferredFlushTags = true;
  1264   } else if (sNotifyOnTimer && mLayoutStarted) {
  1265     if (mBackoffCount && !mInMonolithicContainer) {
  1266       int64_t now = PR_Now();
  1267       int64_t interval = GetNotificationInterval();
  1268       int64_t diff = now - mLastNotificationTime;
  1270       // If it's already time for us to have a notification
  1271       if (diff > interval || mDroppedTimer) {
  1272         mBackoffCount--;
  1273         SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1274                    ("nsContentSink::WillInterrupt: flushing tags since we've "
  1275                     "run out time; backoff count: %d", mBackoffCount));
  1276         result = FlushTags();
  1277         if (mDroppedTimer) {
  1278           ScrollToRef();
  1279           mDroppedTimer = false;
  1281       } else if (!mNotificationTimer) {
  1282         interval -= diff;
  1283         int32_t delay = interval;
  1285         // Convert to milliseconds
  1286         delay /= PR_USEC_PER_MSEC;
  1288         mNotificationTimer = do_CreateInstance("@mozilla.org/timer;1",
  1289                                                &result);
  1290         if (NS_SUCCEEDED(result)) {
  1291           SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1292                      ("nsContentSink::WillInterrupt: setting up timer with "
  1293                       "delay %d", delay));
  1295           result =
  1296             mNotificationTimer->InitWithCallback(this, delay,
  1297                                                  nsITimer::TYPE_ONE_SHOT);
  1298           if (NS_FAILED(result)) {
  1299             mNotificationTimer = nullptr;
  1304   } else {
  1305     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1306                ("nsContentSink::WillInterrupt: flushing tags "
  1307                 "unconditionally"));
  1308     result = FlushTags();
  1310 #endif
  1312   mParsing = false;
  1314   return result;
  1317 nsresult
  1318 nsContentSink::WillResumeImpl()
  1320   SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
  1321              ("nsContentSink::WillResume: this=%p", this));
  1323   mParsing = true;
  1325   return NS_OK;
  1328 nsresult
  1329 nsContentSink::DidProcessATokenImpl()
  1331   if (mRunsToCompletion || !mParser) {
  1332     return NS_OK;
  1335   // Get the current user event time
  1336   nsIPresShell *shell = mDocument->GetShell();
  1337   if (!shell) {
  1338     // If there's no pres shell in the document, return early since
  1339     // we're not laying anything out here.
  1340     return NS_OK;
  1343   // Increase before comparing to gEventProbeRate
  1344   ++mDeflectedCount;
  1346   // Check if there's a pending event
  1347   if (sPendingEventMode != 0 && !mHasPendingEvent &&
  1348       (mDeflectedCount % sEventProbeRate) == 0) {
  1349     nsViewManager* vm = shell->GetViewManager();
  1350     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
  1351     nsCOMPtr<nsIWidget> widget;
  1352     vm->GetRootWidget(getter_AddRefs(widget));
  1353     mHasPendingEvent = widget && widget->HasPendingInputEvent();
  1356   if (mHasPendingEvent && sPendingEventMode == 2) {
  1357     return NS_ERROR_HTMLPARSER_INTERRUPTED;
  1360   // Have we processed enough tokens to check time?
  1361   if (!mHasPendingEvent &&
  1362       mDeflectedCount < uint32_t(mDynamicLowerValue ? sInteractiveDeflectCount :
  1363                                                       sPerfDeflectCount)) {
  1364     return NS_OK;
  1367   mDeflectedCount = 0;
  1369   // Check if it's time to return to the main event loop
  1370   if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
  1371     return NS_ERROR_HTMLPARSER_INTERRUPTED;
  1374   return NS_OK;
  1377 //----------------------------------------------------------------------
  1379 void
  1380 nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
  1382   static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
  1383   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
  1384   if (appShell)
  1385     appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
  1388 void
  1389 nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
  1391   // Remember nested updates from updates that we started.
  1392   if (mInNotification > 0 && mUpdatesInNotification < 2) {
  1393     ++mUpdatesInNotification;
  1396   // If we're in a script and we didn't do the notification,
  1397   // something else in the script processing caused the
  1398   // notification to occur. Since this could result in frame
  1399   // creation, make sure we've flushed everything before we
  1400   // continue.
  1402   if (!mInNotification++) {
  1403     FlushTags();
  1407 void
  1408 nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
  1410   // If we're in a script and we didn't do the notification,
  1411   // something else in the script processing caused the
  1412   // notification to occur. Update our notion of how much
  1413   // has been flushed to include any new content if ending
  1414   // this update leaves us not inside a notification.
  1415   if (!--mInNotification) {
  1416     UpdateChildCounts();
  1420 void
  1421 nsContentSink::DidBuildModelImpl(bool aTerminated)
  1423   if (mDocument) {
  1424     MOZ_ASSERT(aTerminated ||
  1425                mDocument->GetReadyStateEnum() ==
  1426                nsIDocument::READYSTATE_LOADING, "Bad readyState");
  1427     mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
  1430   if (mScriptLoader) {
  1431     mScriptLoader->ParsingComplete(aTerminated);
  1434   if (!mDocument->HaveFiredDOMTitleChange()) {
  1435     mDocument->NotifyPossibleTitleChange(false);
  1438   // Cancel a timer if we had one out there
  1439   if (mNotificationTimer) {
  1440     SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
  1441                ("nsContentSink::DidBuildModel: canceling notification "
  1442                 "timeout"));
  1443     mNotificationTimer->Cancel();
  1444     mNotificationTimer = 0;
  1448 void
  1449 nsContentSink::DropParserAndPerfHint(void)
  1451   if (!mParser) {
  1452     // Make sure we don't unblock unload too many times
  1453     return;
  1456   // Ref. Bug 49115
  1457   // Do this hack to make sure that the parser
  1458   // doesn't get destroyed, accidently, before
  1459   // the circularity, between sink & parser, is
  1460   // actually broken.
  1461   // Drop our reference to the parser to get rid of a circular
  1462   // reference.
  1463   nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
  1465   if (mDynamicLowerValue) {
  1466     // Reset the performance hint which was set to FALSE
  1467     // when mDynamicLowerValue was set.
  1468     FavorPerformanceHint(true, 0);
  1471   if (!mRunsToCompletion) {
  1472     mDocument->UnblockOnload(true);
  1476 bool
  1477 nsContentSink::IsScriptExecutingImpl()
  1479   return !!mScriptLoader->GetCurrentScript();
  1482 nsresult
  1483 nsContentSink::WillParseImpl(void)
  1485   if (mRunsToCompletion || !mDocument) {
  1486     return NS_OK;
  1489   nsIPresShell *shell = mDocument->GetShell();
  1490   if (!shell) {
  1491     return NS_OK;
  1494   uint32_t currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  1496   if (sEnablePerfMode == 0) {
  1497     nsViewManager* vm = shell->GetViewManager();
  1498     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
  1499     uint32_t lastEventTime;
  1500     vm->GetLastUserEventTime(lastEventTime);
  1502     bool newDynLower =
  1503       mDocument->IsInBackgroundWindow() ||
  1504       ((currentTime - mBeginLoadTime) > uint32_t(sInitialPerfTime) &&
  1505        (currentTime - lastEventTime) < uint32_t(sInteractiveTime));
  1507     if (mDynamicLowerValue != newDynLower) {
  1508       FavorPerformanceHint(!newDynLower, 0);
  1509       mDynamicLowerValue = newDynLower;
  1513   mDeflectedCount = 0;
  1514   mHasPendingEvent = false;
  1516   mCurrentParseEndTime = currentTime +
  1517     (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
  1519   return NS_OK;
  1522 void
  1523 nsContentSink::WillBuildModelImpl()
  1525   if (!mRunsToCompletion) {
  1526     mDocument->BlockOnload();
  1528     mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  1531   mDocument->ResetScrolledToRefAlready();
  1533   if (mProcessLinkHeaderEvent.get()) {
  1534     mProcessLinkHeaderEvent.Revoke();
  1536     DoProcessLinkHeader();
  1540 /* static */
  1541 void
  1542 nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
  1544   nsCOMPtr<nsIObserverService> observerService =
  1545     mozilla::services::GetObserverService();
  1546   if (observerService) {
  1547     nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
  1548     observerService->
  1549       NotifyObservers(domDoc, "document-element-inserted",
  1550                       EmptyString().get());

mercurial