[go: nahoru, domu]

blob: 7ac27a975291bbcf3996378dc03101be521e191d [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/loader/render_blocking_resource_manager.h"
#include "base/test/scoped_feature_list.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
class RenderBlockingResourceManagerTest : public SimTest {
public:
static Vector<char> ReadAhemWoff2() {
return test::ReadFromFile(test::CoreTestDataPath("Ahem.woff2"))
->CopyAs<Vector<char>>();
}
protected:
RenderBlockingResourceManager& GetRenderBlockingResourceManager() {
return *GetDocument().GetRenderBlockingResourceManager();
}
bool HasRenderBlockingResources() {
return GetRenderBlockingResourceManager().HasRenderBlockingResources();
}
void DisableFontPreloadTimeout() {
GetRenderBlockingResourceManager().DisableFontPreloadTimeoutForTest();
}
void SetFontPreloadTimeout(base::TimeDelta timeout) {
GetRenderBlockingResourceManager().SetFontPreloadTimeoutForTest(timeout);
}
bool FontPreloadTimerIsActive() {
return GetRenderBlockingResourceManager().FontPreloadTimerIsActiveForTest();
}
Element* GetTarget() {
return GetDocument().getElementById(AtomicString("target"));
}
const Font& GetTargetFont() {
return GetTarget()->GetLayoutObject()->Style()->GetFont();
}
};
TEST_F(RenderBlockingResourceManagerTest, FastFontFinishBeforeBody) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<head>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/font.woff">
)HTML");
// Make sure timer doesn't fire in case the test runs slow.
SetFontPreloadTimeout(base::Seconds(30));
// Rendering is blocked due to ongoing font preloading.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
font_resource.Complete();
test::RunPendingTasks();
// Font preloading no longer blocks renderings. However, rendering is still
// blocked, as we don't have BODY yet.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
main_resource.Complete("</head><body>some text</body>");
// Rendering starts after BODY has arrived, as the font was loaded earlier.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
}
TEST_F(RenderBlockingResourceManagerTest, FastFontFinishAfterBody) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<head>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/font.woff">
)HTML");
// Rendering is blocked due to ongoing font preloading.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
main_resource.Complete("</head><body>some text</body>");
// Rendering is still blocked by font, even if we already have BODY, because
// the font was *not* loaded earlier.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
font_resource.Complete();
test::RunPendingTasks();
// Rendering starts after font preloading has finished.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
}
TEST_F(RenderBlockingResourceManagerTest, SlowFontTimeoutBeforeBody) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<head>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/font.woff">
)HTML");
// Rendering is blocked due to ongoing font preloading.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
GetRenderBlockingResourceManager().FontPreloadingTimerFired(nullptr);
// Font preloading no longer blocks renderings after the timeout fires.
// However, rendering is still blocked, as we don't have BODY yet.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
main_resource.Complete("</head><body>some text</body>");
// Rendering starts after BODY has arrived.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
font_resource.Complete();
}
TEST_F(RenderBlockingResourceManagerTest, SlowFontTimeoutAfterBody) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<head>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/font.woff">
)HTML");
// Rendering is blocked due to ongoing font preloading.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
main_resource.Complete("</head><body>some text</body>");
// Rendering is still blocked by font, even if we already have BODY.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
GetRenderBlockingResourceManager().FontPreloadingTimerFired(nullptr);
// Rendering starts after we've waited for the font preloading long enough.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
font_resource.Complete();
}
// A trivial test case to verify test setup
TEST_F(RenderBlockingResourceManagerTest, RegularWebFont) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target style="position:relative">0123456789</span>
)HTML");
// Now rendering has started, as there's no blocking resources.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
// Now everything is loaded. The web font should be used in rendering.
Compositor().BeginFrame().DrawCount();
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontWithoutPreloading) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
<script>document.fonts.load('25px/1 custom-font');</script>
)HTML");
// Now rendering has started, as there's no blocking resources.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
// Although the optional web font isn't preloaded, it finished loading before
// the first time we try to render with it. Therefore it's used.
Compositor().BeginFrame().Contains(SimCanvas::kText);
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
main_resource.Finish();
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontMissingFirstFrame) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
)HTML");
// Now rendering has started, as there's no blocking resources.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
// We render visible fallback as the 'optional' web font hasn't loaded.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
font_resource.Complete(ReadAhemWoff2());
// Since we have rendered fallback for the 'optional' font, even after it
// finishes loading, we shouldn't use it, as otherwise there's a relayout.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
main_resource.Finish();
}
TEST_F(RenderBlockingResourceManagerTest,
OptionalFontForcedLayoutNoLayoutShift) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
<span>Element to track layout shift when font changes</span>
)HTML");
// Now rendering has started, as there's no blocking resources.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
// Force layout update, which lays out target but doesn't paint anything.
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
test::RunPendingTasks();
EXPECT_GT(250, GetTarget()->OffsetWidth());
// Can't check ShouldSkipDrawing(), as it calls PaintRequested() on the font.
font_resource.Complete(ReadAhemWoff2());
// Even though target has been laid out with a fallback font, we can still
// relayout with the web font since it hasn't been painted yet, which means
// relayout and repaint do not cause layout shifting.
Compositor().BeginFrame();
test::RunPendingTasks();
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
EXPECT_EQ(0.0, GetDocument().View()->GetLayoutShiftTracker().Score());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontRemoveAndReadd) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
)HTML");
// Now rendering has started, as there's no blocking resources.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
// The 'optional' web font isn't used, as it didn't finish loading before
// rendering started. Text is rendered in visible fallback.
Compositor().BeginFrame().Contains(SimCanvas::kText);
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
font_resource.Complete(ReadAhemWoff2());
Element* style = GetDocument().QuerySelector(AtomicString("style"));
style->remove();
GetDocument().head()->appendChild(style);
// After removing and readding the style sheet, we've created a new font face
// that got loaded immediately from the memory cache. So it can be used.
Compositor().BeginFrame().Contains(SimCanvas::kText);
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontSlowPreloading) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/Ahem.woff2" crossorigin>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
)HTML");
// Rendering is blocked due to font being preloaded.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
GetRenderBlockingResourceManager().FontPreloadingTimerFired(nullptr);
// Rendering is unblocked after the font preloading has timed out.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
// First frame renders text with visible fallback, as the 'optional' web font
// isn't loaded yet, and should be treated as in the failure period.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
font_resource.Complete(ReadAhemWoff2());
// The 'optional' web font should not cause relayout even if it finishes
// loading now.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontFastPreloading) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2"
href="https://example.com/Ahem.woff2" crossorigin>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<span id=target>0123456789</span>
)HTML");
// Rendering is blocked due to font being preloaded.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
// There are test flakes due to RenderBlockingResourceManager timeout firing
// before the ResourceFinishObserver gets notified. So we disable the timeout.
DisableFontPreloadTimeout();
font_resource.Complete(ReadAhemWoff2());
test::RunPendingTasks();
// Rendering is unblocked after the font is preloaded.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
// The 'optional' web font should be used in the first paint.
Compositor().BeginFrame();
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontSlowImperativeLoad) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<script>
document.fonts.load('25px/1 custom-font');
</script>
<span id=target>0123456789</span>
)HTML");
// Rendering is blocked due to font being loaded via JavaScript API.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
GetRenderBlockingResourceManager().FontPreloadingTimerFired(nullptr);
// Rendering is unblocked after the font preloading has timed out.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
// First frame renders text with visible fallback, as the 'optional' web font
// isn't loaded yet, and should be treated as in the failure period.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
font_resource.Complete(ReadAhemWoff2());
// The 'optional' web font should not cause relayout even if it finishes
// loading now.
Compositor().BeginFrame();
EXPECT_GT(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, OptionalFontFastImperativeLoad) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/Ahem.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<style>
@font-face {
font-family: custom-font;
src: url(https://example.com/Ahem.woff2) format("woff2");
font-display: optional;
}
#target {
font: 25px/1 custom-font, monospace;
}
</style>
<script>
document.fonts.load('25px/1 custom-font');
</script>
<span id=target>0123456789</span>
)HTML");
// Make sure timer doesn't fire in case the test runs slow.
SetFontPreloadTimeout(base::Seconds(30));
// Rendering is blocked due to font being preloaded.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
EXPECT_TRUE(HasRenderBlockingResources());
font_resource.Complete(ReadAhemWoff2());
test::RunPendingTasks();
// Rendering is unblocked after the font is preloaded.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
EXPECT_FALSE(HasRenderBlockingResources());
// The 'optional' web font should be used in the first paint.
Compositor().BeginFrame();
EXPECT_EQ(250, GetTarget()->OffsetWidth());
EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
}
TEST_F(RenderBlockingResourceManagerTest, ScriptInsertedBodyUnblocksRendering) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest style_resource("https://example.com/sheet.css",
"text/css");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<link rel="stylesheet" href="sheet.css">
)HTML");
Element* body = GetDocument().CreateElementForBinding(AtomicString("body"));
GetDocument().setBody(To<HTMLElement>(body), ASSERT_NO_EXCEPTION);
// Rendering should be blocked by the pending stylesheet.
EXPECT_TRUE(GetDocument().body());
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
style_resource.Complete("body { width: 100px; }");
// Rendering should be unblocked as all render-blocking resources are loaded
// and there is a body, even though it's not inserted by parser.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
Compositor().BeginFrame();
EXPECT_EQ(100, GetDocument().body()->OffsetWidth());
main_resource.Finish();
}
// https://crbug.com/1308083
TEST_F(RenderBlockingResourceManagerTest, ParserBlockingScriptBeforeFont) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
SimSubresourceRequest script_resource("https://example.com/script.js",
"application/javascript");
LoadURL("https://example.com");
// Make sure timer doesn't fire in case the test runs slow.
SetFontPreloadTimeout(base::Seconds(30));
main_resource.Complete(R"HTML(
<!doctype html>
<script src="script.js"></script>
<link rel="preload" as="font" type="font/woff2"
href="font.woff2" crossorigin>
<div>
Lorem ipsum
</div>
)HTML");
// Rendering is still blocked.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
// Parser is blocked by the synchronous script, so <link> isn't inserted yet.
EXPECT_FALSE(GetDocument().QuerySelector(AtomicString("link")));
// Preload scanner should have started font preloading and also the timer.
// This should happen before the parser sets up the preload link element.
EXPECT_TRUE(FontPreloadTimerIsActive());
script_resource.Complete();
font_resource.Complete();
}
class RenderBlockingFontTest : public RenderBlockingResourceManagerTest {
public:
void SetUp() override {
// Use a longer timeout to prevent flakiness when test is running slow.
std::map<std::string, std::string> parameters;
parameters["max-fcp-delay"] = "500";
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kRenderBlockingFonts, parameters);
SimTest::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(RenderBlockingFontTest, FastFontPreloadWithoutOtherBlockingResources) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
Body Content
)HTML");
// Rendering is blocked by font.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
test::RunPendingTasks();
// Rendering is unblocked after font preload finishes.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
}
TEST_F(RenderBlockingFontTest, SlowFontPreloadWithoutOtherBlockingResources) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
Body Content
)HTML");
// Rendering is blocked by font.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
// Wait until we've delayed FCP for the max allowed amount of time, and the
// relevant timeout fires.
test::RunDelayedTasks(
base::Milliseconds(features::kMaxFCPDelayMsForRenderBlockingFonts.Get()));
// Rendering is unblocked as max FCP delay is reached.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
}
TEST_F(RenderBlockingFontTest,
SlowFontPreloadAndSlowBodyWithoutOtherBlockingResources) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
LoadURL("https://example.com");
main_resource.Write(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
)HTML");
// Rendering is blocked by font.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
// Wait until we've blocked rendering for the max allowed amount of time since
// navigation, and the relevant timeout fires.
test::RunDelayedTasks(base::Milliseconds(
features::kMaxBlockingTimeMsForRenderBlockingFonts.Get()));
// The font preload is no longer render-blocking, but Rendering is still
// blocked because the document has no body.
EXPECT_FALSE(GetRenderBlockingResourceManager().HasRenderBlockingFonts());
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
main_resource.Complete("Body Content");
// Rendering is unblocked after body is inserted.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
}
TEST_F(RenderBlockingFontTest, FastFontPreloadWithOtherBlockingResources) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
SimSubresourceRequest css_resource("https://example.com/style.css",
"text/css");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
<link rel="stylesheet" href="https://example.com/style.css">
Body Content
)HTML");
font_resource.Complete(ReadAhemWoff2());
test::RunPendingTasks();
// Rendering is still blocked by the style sheet.
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
css_resource.Complete("body { color: red; }");
test::RunPendingTasks();
// Rendering is unblocked after all resources are loaded.
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
}
TEST_F(RenderBlockingFontTest, FontPreloadExceedingMaxBlockingTime) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
SimSubresourceRequest css_resource("https://example.com/style.css",
"text/css");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
<link rel="stylesheet" href="https://example.com/style.css">
Body Content
)HTML");
// Wait until we've blocked rendering for the max allowed amount of time since
// navigation, and the relevant timeout fires.
test::RunDelayedTasks(base::Milliseconds(
features::kMaxBlockingTimeMsForRenderBlockingFonts.Get()));
// The font preload is no longer render-blocking, but we still have a
// render-blocking style sheet.
EXPECT_FALSE(GetRenderBlockingResourceManager().HasRenderBlockingFonts());
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
css_resource.Complete("body { color: red; }");
test::RunPendingTasks();
// Rendering is unblocked after the style sheet is loaded.
EXPECT_FALSE(GetRenderBlockingResourceManager().HasRenderBlockingFonts());
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
}
TEST_F(RenderBlockingFontTest, FontPreloadExceedingMaxFCPDelay) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
SimSubresourceRequest css_resource("https://example.com/style.css",
"text/css");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
<link rel="stylesheet" href="https://example.com/style.css">
Body Content
)HTML");
css_resource.Complete("body { color: red; }");
test::RunPendingTasks();
// Now the font is the only render-blocking resource, and rendering would have
// started without the font.
EXPECT_TRUE(GetRenderBlockingResourceManager().HasRenderBlockingFonts());
EXPECT_FALSE(
GetRenderBlockingResourceManager().HasNonFontRenderBlockingResources());
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
test::RunDelayedTasks(
base::Milliseconds(features::kMaxFCPDelayMsForRenderBlockingFonts.Get()));
// After delaying FCP for the max allowed time, the font is no longer
// render-blocking.
EXPECT_FALSE(GetRenderBlockingResourceManager().HasRenderBlockingFonts());
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
}
TEST_F(RenderBlockingFontTest, FontPreloadExceedingBothLimits) {
SimRequest main_resource("https://example.com", "text/html");
SimSubresourceRequest font_resource("https://example.com/font.woff2",
"font/woff2");
SimSubresourceRequest css_resource("https://example.com/style.css",
"text/css");
LoadURL("https://example.com");
main_resource.Complete(R"HTML(
<!doctype html>
<link rel="preload" as="font" type="font/woff2" crossorigin
href="https://example.com/font.woff2">
<link rel="stylesheet" href="https://example.com/style.css">
Body Content
)HTML");
css_resource.Complete("body { color: red; }");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
test::RunDelayedTasks(
base::Milliseconds(features::kMaxFCPDelayMsForRenderBlockingFonts.Get()));
test::RunDelayedTasks(base::Milliseconds(
features::kMaxBlockingTimeMsForRenderBlockingFonts.Get()));
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
font_resource.Complete(ReadAhemWoff2());
}
} // namespace blink