Enable WebFonts cache-aware timeout adaption

Enable the feature by default, but with a FeatureList kill-switch.

Bug: 570205
Change-Id: I003c21871ab71e47a863707b9709a39d76883635
Reviewed-on: https://chromium-review.googlesource.com/c/1429820
Reviewed-by: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Takashi Toyoshima <toyoshim@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#626969}(cherry picked from commit 67bee39340b5b4f5b361a0423391c044d13dd332)
Reviewed-on: https://chromium-review.googlesource.com/c/1446263
Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org>
Cr-Commit-Position: refs/branch-heads/3683@{#85}
Cr-Branched-From: e51029943e0a38dd794b73caaf6373d5496ae783-refs/heads/master@{#625896}
diff --git a/chrome/test/data/extensions/api_test/webrequest/framework.js b/chrome/test/data/extensions/api_test/webrequest/framework.js
index 1050b67..17e8804 100644
--- a/chrome/test/data/extensions/api_test/webrequest/framework.js
+++ b/chrome/test/data/extensions/api_test/webrequest/framework.js
@@ -132,7 +132,7 @@
   chrome.tabs.update(tabId, {url: url});
 }
 
-// data: array of extected events, each one is a dictionary:
+// data: array of expected events, each one is a dictionary:
 //     { label: "<unique identifier>",
 //       event: "<webrequest event type>",
 //       details: { <expected details of the webrequest event> },
@@ -345,14 +345,25 @@
     delete details.responseHeaders;
   }
 
+  // Check if the equivalent event is already captured, and issue a unique
+  // |eventCount| to identify each.
+  var eventCount = 0;
+  capturedEventData.forEach(function (event) {
+    if (deepEq(event.event, name) && deepEq(event.details, details)) {
+      eventCount++;
+      // update |details| for the next match.
+      details.eventCount = eventCount;
+    }
+  });
+
   // find |details| in expectedEventData
   var found = false;
   var label = undefined;
   expectedEventData.forEach(function (exp) {
     if (deepEq(exp.event, name) && deepEq(exp.details, details)) {
       if (found) {
-        chrome.test.fail("Received event twice '" + name + "':" +
-            JSON.stringify(details));
+        chrome.test.fail("Duplicated expectation entry '" + exp.label +
+        "' should be identified by |eventCount|: " + JSON.stringify(details));
       } else {
         found = true;
         label = exp.label;
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_types.js b/chrome/test/data/extensions/api_test/webrequest/test_types.js
index 70d2a4c..87f4ac5 100644
--- a/chrome/test/data/extensions/api_test/webrequest/test_types.js
+++ b/chrome/test/data/extensions/api_test/webrequest/test_types.js
@@ -255,7 +255,7 @@
           url: getFontURL(),
           tabId: 1,
           initiator: getDomain(initiators.WEB_INITIATED)
-        },
+        }
       },
       { label: 'onSendHeaders',
         event: 'onSendHeaders',
@@ -264,7 +264,49 @@
           url: getFontURL(),
           tabId: 1,
           initiator: getDomain(initiators.WEB_INITIATED)
-        },
+        }
+      },
+      { label: 'onErrorOccurred',
+        event: 'onErrorOccurred',
+        details: {
+          type: 'font',
+          url: getFontURL(),
+          tabId: 1,
+          initiator: getDomain(initiators.WEB_INITIATED),
+          error: 'net::ERR_CACHE_MISS',
+          fromCache: false,
+        }
+      },
+      { label: 'onBeforeRequest-1',
+        event: 'onBeforeRequest',
+        details: {
+          eventCount: 1,
+          type: 'font',
+          url: getFontURL(),
+          frameUrl: 'unknown frame URL',
+          tabId: 1,
+          initiator: getDomain(initiators.WEB_INITIATED)
+        }
+      },
+      { label: 'onBeforeSendHeaders-1',
+        event: 'onBeforeSendHeaders',
+        details: {
+          eventCount: 1,
+          type: 'font',
+          url: getFontURL(),
+          tabId: 1,
+          initiator: getDomain(initiators.WEB_INITIATED)
+        }
+      },
+      { label: 'onSendHeaders-1',
+        event: 'onSendHeaders',
+        details: {
+          eventCount: 1,
+          type: 'font',
+          url: getFontURL(),
+          tabId: 1,
+          initiator: getDomain(initiators.WEB_INITIATED)
+        }
       },
       { label: 'onHeadersReceived',
         event: 'onHeadersReceived',
@@ -275,7 +317,7 @@
           statusLine: 'HTTP/1.1 200 OK',
           statusCode: 200,
           initiator: getDomain(initiators.WEB_INITIATED)
-        },
+        }
       },
       { label: 'onResponseStarted',
         event: 'onResponseStarted',
@@ -288,7 +330,7 @@
           statusLine: 'HTTP/1.1 200 OK',
           statusCode: 200,
           initiator: getDomain(initiators.WEB_INITIATED)
-        },
+        }
       },
       { label: 'onCompleted',
         event: 'onCompleted',
@@ -301,10 +343,12 @@
           statusLine: 'HTTP/1.1 200 OK',
           statusCode: 200,
           initiator: getDomain(initiators.WEB_INITIATED)
-        },
+        }
       }],
       [['onBeforeRequest', 'onBeforeSendHeaders', 'onSendHeaders',
-        'onHeadersReceived', 'onResponseStarted', 'onCompleted']],
+        'onErrorOccurred', 'onBeforeRequest-1', 'onBeforeSendHeaders-1',
+        'onSendHeaders-1', 'onHeadersReceived', 'onResponseStarted',
+        'onCompleted']],
       {urls: [getFontURL()]});
 
     // Load a page to be sure webRequest listeners are set up.
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 33fe813..1802700 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -180,5 +180,9 @@
 const base::Feature kAlwaysAccelerateCanvas{"AlwaysAccelerateCanvas",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables cache-aware WebFonts loading. See https://crbug.com/570205.
+const base::Feature kWebFontsCacheAwareTimeoutAdaption{
+    "WebFontsCacheAwareTimeoutAdaption", base::FEATURE_ENABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index ce0bbdc..7eec8dc 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -60,6 +60,9 @@
 BLINK_COMMON_EXPORT extern const base::Feature kDecodeLossyWebPImagesToYUV;
 BLINK_COMMON_EXPORT extern const base::Feature kAlwaysAccelerateCanvas;
 
+BLINK_COMMON_EXPORT extern const base::Feature
+    kWebFontsCacheAwareTimeoutAdaption;
+
 }  // namespace features
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/css/css_font_face_src_value.cc b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
index c1843a3..3db4ccb 100644
--- a/third_party/blink/renderer/core/css/css_font_face_src_value.cc
+++ b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
@@ -25,6 +25,8 @@
 
 #include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
 
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/core/css/css_markup.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -88,8 +90,10 @@
     ResourceLoaderOptions options;
     options.initiator_info.name = fetch_initiator_type_names::kCSS;
     FetchParameters params(resource_request, options);
-    if (RuntimeEnabledFeatures::WebFontsCacheAwareTimeoutAdaptationEnabled())
+    if (base::FeatureList::IsEnabled(
+            features::kWebFontsCacheAwareTimeoutAdaption)) {
       params.SetCacheAwareLoadingEnabled(kIsCacheAwareLoadingEnabled);
+    }
     params.SetContentSecurityCheck(should_check_content_security_policy_);
     const SecurityOrigin* security_origin = context->GetSecurityOrigin();
 
diff --git a/third_party/blink/renderer/core/loader/resource/font_resource.h b/third_party/blink/renderer/core/loader/resource/font_resource.h
index d5f2b7c..d07e856 100644
--- a/third_party/blink/renderer/core/loader/resource/font_resource.h
+++ b/third_party/blink/renderer/core/loader/resource/font_resource.h
@@ -106,7 +106,7 @@
   TaskHandle font_load_long_limit_;
 
   friend class MemoryCache;
-  FRIEND_TEST_ALL_PREFIXES(FontResourceTest, CacheAwareFontLoading);
+  FRIEND_TEST_ALL_PREFIXES(CacheAwareFontResourceTest, CacheAwareFontLoading);
 };
 
 DEFINE_RESOURCE_TYPE_CASTS(Font);
diff --git a/third_party/blink/renderer/core/loader/resource/font_resource_test.cc b/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
index faff11f..82a304b 100644
--- a/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
@@ -4,7 +4,9 @@
 
 #include "third_party/blink/renderer/core/loader/resource/font_resource.h"
 
+#include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
@@ -36,6 +38,18 @@
   }
 };
 
+class CacheAwareFontResourceTest : public FontResourceTest {
+ public:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kWebFontsCacheAwareTimeoutAdaption);
+    FontResourceTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 // Tests if ResourceFetcher works fine with FontResource that requires defered
 // loading supports.
 TEST_F(FontResourceTest,
@@ -98,16 +112,13 @@
 }
 
 // Tests if cache-aware font loading works correctly.
-TEST_F(FontResourceTest, CacheAwareFontLoading) {
+TEST_F(CacheAwareFontResourceTest, CacheAwareFontLoading) {
   KURL url("http://127.0.0.1:8000/font.woff");
   ResourceResponse response(url);
   response.SetHTTPStatusCode(200);
   Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(
       url, WrappedResourceResponse(response), "");
 
-  RuntimeEnabledFeatures::Backup features_backup;
-  RuntimeEnabledFeatures::SetWebFontsCacheAwareTimeoutAdaptationEnabled(true);
-
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       DummyPageHolder::Create(IntSize(800, 600));
   Document& document = dummy_page_holder->GetDocument();
@@ -166,8 +177,6 @@
 
   Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
   GetMemoryCache()->Remove(&resource);
-
-  features_backup.Restore();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 788fc07..a44757a0 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1396,10 +1396,6 @@
       status: "test",
     },
     {
-      name: "WebFontsCacheAwareTimeoutAdaptation",
-      status: "experimental",
-    },
-    {
       name: "WebGL2ComputeContext",
       status: "experimental",
     },