Bug 1585674 - Start loads more incrementally in the @import scanner. r=hsivonen
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 03 Oct 2019 07:34:35 +0000
changeset 496192 05bd576d46f50a6843759329b4b6218fe07aeae4
parent 496191 033ed04462d0a9d6d6466502610ad55f94a92c14
child 496193 3e0f997b9cfe0c9299610c5eb34fda56c7ce2dbd
push id36646
push usernerli@mozilla.com
push dateThu, 03 Oct 2019 21:48:01 +0000
treeherdermozilla-central@2e1bfb7458de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1585674
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1585674 - Start loads more incrementally in the @import scanner. r=hsivonen Consider the case of a very big <style> element, with a few imports on top, which we cut half-way over the network. The @import scanner would be likely to have found anything there is to be found, but we won't process it until we pop the <style> element. It's relatively low effort to support this use-case by making Scan() return the already-found urls. Differential Revision: https://phabricator.services.mozilla.com/D47914
layout/style/ImportScanner.cpp
layout/style/ImportScanner.h
layout/style/test/gtest/ImportScannerTest.cpp
parser/html/nsHtml5TreeBuilderCppSupplement.h
--- a/layout/style/ImportScanner.cpp
+++ b/layout/style/ImportScanner.cpp
@@ -41,26 +41,27 @@ nsTArray<nsString> ImportScanner::Stop()
   }
   mState = State::OutsideOfStyleElement;
   mInImportRule = false;
   mRuleName.Truncate(0);
   mRuleValue.Truncate(0);
   return std::move(mUrlsFound);
 }
 
-void ImportScanner::DoScan(Span<const char16_t> aFragment) {
-  MOZ_ASSERT(mState != State::OutsideOfStyleElement);
-  MOZ_ASSERT(mState != State::Done);
+nsTArray<nsString> ImportScanner::Scan(Span<const char16_t> aFragment) {
+  MOZ_ASSERT(ShouldScan());
 
   for (char16_t c : aFragment) {
     mState = Scan(c);
     if (mState == State::Done) {
-      return;
+      break;
     }
   }
+
+  return std::move(mUrlsFound);
 }
 
 auto ImportScanner::Scan(char16_t aChar) -> State {
   switch (mState) {
     case State::OutsideOfStyleElement:
     case State::Done:
       MOZ_ASSERT_UNREACHABLE("How?");
       return mState;
--- a/layout/style/ImportScanner.h
+++ b/layout/style/ImportScanner.h
@@ -21,24 +21,27 @@ struct ImportScanner final {
   //
   // Note that this function cannot make assumptions about the internal state,
   // as you can nest <svg:style> elements.
   void Start();
 
   // Called when a <style> element ends. Returns the list of URLs scanned.
   nsTArray<nsString> Stop();
 
-  // Scan() should be called when text content is parsed.
-  void Scan(Span<const char16_t> aFragment) {
-    if (mState == State::OutsideOfStyleElement || mState == State::Done) {
-      return;
-    }
-    DoScan(aFragment);
+  // Whether Scan() should be called.
+  bool ShouldScan() const {
+    return mState != State::OutsideOfStyleElement && mState != State::Done;
   }
 
+  // Scan() should be called when text content is parsed, and returns an array
+  // of found URLs, if any.
+  //
+  // Asserts ShouldScan() returns true.
+  nsTArray<nsString> Scan(Span<const char16_t> aFragment);
+
  private:
   enum class State {
     // Initial state, doesn't scan anything until Start() is called.
     OutsideOfStyleElement,
     // In an idle state during the stylesheet scanning, either at the
     // beginning or after parsing a rule.
     Idle,
     // We've seen a '/' character, but not the '*' yet, so we don't know if
@@ -59,17 +62,16 @@ struct ImportScanner final {
     // We've seen the url, but haven't seen the ';' finishing the rule yet.
     AfterRuleValue,
     // We've seen anything that is not an @import or a @charset rule, and thus
     // further @import / @charset should not be parsed.
     Done,
   };
 
   void EmitUrl();
-  void DoScan(Span<const char16_t> aFragment);
   MOZ_MUST_USE State Scan(char16_t aChar);
 
   static constexpr const uint32_t kMaxRuleNameLength = 7;  // (charset, import)
 
   State mState = State::OutsideOfStyleElement;
   nsAutoStringN<kMaxRuleNameLength> mRuleName;
   nsAutoStringN<128> mRuleValue;
   nsTArray<nsString> mUrlsFound;
--- a/layout/style/test/gtest/ImportScannerTest.cpp
+++ b/layout/style/test/gtest/ImportScannerTest.cpp
@@ -5,20 +5,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gtest/gtest.h"
 #include "mozilla/ImportScanner.h"
 
 using namespace mozilla;
 
 static nsTArray<nsString> Scan(const char* aCssCode) {
+  nsTArray<nsString> urls;
   ImportScanner scanner;
   scanner.Start();
-  scanner.Scan(NS_ConvertUTF8toUTF16(aCssCode));
-  return scanner.Stop();
+  urls.AppendElements(scanner.Scan(NS_ConvertUTF8toUTF16(aCssCode)));
+  urls.AppendElements(scanner.Stop());
+  return urls;
 }
 
 TEST(ImportScanner, Simple)
 {
   auto urls = Scan("/* Something something */ "
       "@charset \"utf-8\";"
       "@import url(bar);"
       "@import uRL( baz );"
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -673,17 +673,23 @@ void nsHtml5TreeBuilder::appendCharacter
     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
     mBroken = NS_ERROR_OUT_OF_MEMORY;
     requestSuspension();
     return;
   }
 
   memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
 
-  mImportScanner.Scan(MakeSpan(aBuffer, aLength));
+  if (mImportScanner.ShouldScan()) {
+    nsTArray<nsString> imports =
+        mImportScanner.Scan(MakeSpan(aBuffer, aLength));
+    for (nsString& url : imports) {
+      mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url));
+    }
+  }
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   if (MOZ_UNLIKELY(!treeOp)) {
     MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
   opAppendText operation(aParent, bufferCopy.release(), aLength);
   treeOp->Init(mozilla::AsVariant(operation));