TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyMissingPump) { SimRequest mainResource("https://example.com/index.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.start(); // Write <200 characters. mainResource.write("less than 200 characters."); compositor().beginFrame(); mainResource.finish(); // Even though the layout state is clean ... EXPECT_TRUE(document().lifecycle().state() >= DocumentLifecycle::LayoutClean); // We should still generate a request for another (possibly last) frame. EXPECT_TRUE(compositor().needsAnimate()); // ... which we (the scheduler) happily provide. compositor().beginFrame(); // ... which correctly signals the VisuallyNonEmpty. EXPECT_TRUE(webViewClient().hadVisuallyNonEmptyLayout()); }
TEST_F(WebMeaningfulLayoutsTest, FinishedParsingThenLoading) { SimRequest mainResource("https://example.com/index.html", "text/html"); SimRequest imageResource("https://example.com/cat.png", "image/png"); loadURL("https://example.com/index.html"); mainResource.start(); mainResource.write("<img src=cat.png>"); mainResource.finish(); compositor().beginFrame(); EXPECT_TRUE(webViewClient().hadFinishedParsingLayout()); EXPECT_FALSE(webViewClient().hadFinishedLoadingLayout()); imageResource.complete("image data"); // Pump the message loop to process the image loading task. testing::runPendingTasks(); compositor().beginFrame(); EXPECT_TRUE(webViewClient().hadFinishedLoadingLayout()); }
TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharactersEventually) { SimRequest mainResource("https://example.com/index.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.start(); // Write 200 characters. const char* tenCharacters = "0123456789"; for (int i = 0; i < 20; ++i) mainResource.write(tenCharacters); // Pump a frame mid-load. compositor().beginFrame(); EXPECT_FALSE(webViewClient().hadVisuallyNonEmptyLayout()); // Write more than 200 characters. mainResource.write("!"); mainResource.finish(); // setting visually non-empty happens when the parsing finishes, // not as the character count goes over 200. compositor().beginFrame(); EXPECT_TRUE(webViewClient().hadVisuallyNonEmptyLayout()); }
// NoOverflowInIncrementVisuallyNonEmptyPixelCount tests fail if the number of // pixels is calculated in 32-bit integer, because 65536 * 65536 would become 0 // if it was calculated in 32-bit and thus it would be considered as empty. TEST_F(WebMeaningfulLayoutsTest, NoOverflowInIncrementVisuallyNonEmptyPixelCount) { SimRequest mainResource("https://example.com/test.html", "text/html"); SimRequest svgResource("https://example.com/test.svg", "image/svg+xml"); loadURL("https://example.com/test.html"); mainResource.start(); mainResource.write("<DOCTYPE html><body><img src=\"test.svg\">"); // Run pending tasks to initiate the request to test.svg. testing::runPendingTasks(); EXPECT_EQ(0, webViewClient().visuallyNonEmptyLayoutCount()); // We serve the SVG file and check visuallyNonEmptyLayoutCount() before // mainResource.finish() because finishing the main resource causes // |FrameView::m_isVisuallyNonEmpty| to be true and // visuallyNonEmptyLayoutCount() to be 1 irrespective of the SVG sizes. svgResource.start(); svgResource.write( "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"65536\" " "width=\"65536\"></svg>"); svgResource.finish(); compositor().beginFrame(); EXPECT_EQ(1, webViewClient().visuallyNonEmptyLayoutCount()); mainResource.finish(); }
TEST_F(WebMeaningfulLayoutsTest, WithIFrames) { SimRequest mainResource("https://example.com/index.html", "text/html"); SimRequest iframeResource("https://example.com/iframe.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.complete("<iframe src=iframe.html></iframe>"); compositor().beginFrame(); EXPECT_EQ(1, webViewClient().visuallyNonEmptyLayoutCount()); EXPECT_EQ(1, webViewClient().finishedParsingLayoutCount()); EXPECT_EQ(0, webViewClient().finishedLoadingLayoutCount()); iframeResource.complete("iframe data"); // Pump the message loop to process the iframe loading task. testing::runPendingTasks(); compositor().beginFrame(); EXPECT_EQ(1, webViewClient().visuallyNonEmptyLayoutCount()); EXPECT_EQ(1, webViewClient().finishedParsingLayoutCount()); EXPECT_EQ(1, webViewClient().finishedLoadingLayoutCount()); }
TEST_F(WebMeaningfulLayoutsTest, FinishedParsing) { SimRequest mainResource("https://example.com/index.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.complete("content"); compositor().beginFrame(); EXPECT_EQ(1, webViewClient().finishedParsingLayoutCount()); }
TEST_F(WebMeaningfulLayoutsTest, FinishedLoading) { SimRequest mainResource("https://example.com/index.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.start(); mainResource.write("content"); mainResource.finish(); compositor().beginFrame(); EXPECT_TRUE(webViewClient().hadFinishedLoadingLayout()); }
TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharacters) { SimRequest mainResource("https://example.com/index.html", "text/html"); loadURL("https://example.com/index.html"); mainResource.start(); // Write 201 characters. const char* tenCharacters = "0123456789"; for (int i = 0; i < 20; ++i) mainResource.write(tenCharacters); mainResource.write("!"); mainResource.finish(); compositor().beginFrame(); EXPECT_EQ(1, webViewClient().visuallyNonEmptyLayoutCount()); }
TEST_F(IntersectionObserverTest, ObserveSchedulesFrame) { SimRequest mainResource("https://example.com/", "text/html"); loadURL("https://example.com/"); mainResource.complete("<div id='target'></div>"); IntersectionObserverInit observerInit; TrackExceptionState exceptionState; TestIntersectionObserverCallback* observerCallback = new TestIntersectionObserverCallback(document()); IntersectionObserver* observer = IntersectionObserver::create( observerInit, *observerCallback, exceptionState); ASSERT_FALSE(exceptionState.hadException()); compositor().beginFrame(); ASSERT_FALSE(compositor().needsBeginFrame()); EXPECT_TRUE(observer->takeRecords(exceptionState).isEmpty()); EXPECT_EQ(observerCallback->callCount(), 0); Element* target = document().getElementById("target"); ASSERT_TRUE(target); observer->observe(target, exceptionState); EXPECT_TRUE(compositor().needsBeginFrame()); }
bool LegacyWebArchive::extract(CFDictionaryRef dictionary) { ASSERT(dictionary); if (!dictionary) { LOG(Archives, "LegacyWebArchive - Null root CFDictionary, aborting invalid WebArchive"); return false; } CFDictionaryRef mainResourceDict = static_cast<CFDictionaryRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveMainResourceKey)); if (!mainResourceDict) { LOG(Archives, "LegacyWebArchive - No main resource in archive, aborting invalid WebArchive"); return false; } if (CFGetTypeID(mainResourceDict) != CFDictionaryGetTypeID()) { LOG(Archives, "LegacyWebArchive - Main resource is not the expected CFDictionary, aborting invalid WebArchive"); return false; } setMainResource(createResource(mainResourceDict)); if (!mainResource()) { LOG(Archives, "LegacyWebArchive - Failed to parse main resource from CFDictionary or main resource does not exist, aborting invalid WebArchive"); return false; } CFArrayRef subresourceArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubresourcesKey)); if (subresourceArray && CFGetTypeID(subresourceArray) != CFArrayGetTypeID()) { LOG(Archives, "LegacyWebArchive - Subresources is not the expected Array, aborting invalid WebArchive"); return false; } if (subresourceArray) { CFIndex count = CFArrayGetCount(subresourceArray); for (CFIndex i = 0; i < count; ++i) { CFDictionaryRef subresourceDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subresourceArray, i)); if (CFGetTypeID(subresourceDict) != CFDictionaryGetTypeID()) { LOG(Archives, "LegacyWebArchive - Subresource is not expected CFDictionary, aborting invalid WebArchive"); return false; } addSubresource(createResource(subresourceDict)); } } CFArrayRef subframeArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubframeArchivesKey)); if (subframeArray && CFGetTypeID(subframeArray) != CFArrayGetTypeID()) { LOG(Archives, "LegacyWebArchive - Subframe archives is not the expected Array, aborting invalid WebArchive"); return false; } if (subframeArray) { CFIndex count = CFArrayGetCount(subframeArray); for (CFIndex i = 0; i < count; ++i) { CFDictionaryRef subframeDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subframeArray, i)); if (CFGetTypeID(subframeDict) != CFDictionaryGetTypeID()) { LOG(Archives, "LegacyWebArchive - Subframe array is not expected CFDictionary, aborting invalid WebArchive"); return false; } RefPtr<LegacyWebArchive> subframeArchive = create(); if (subframeArchive->extract(subframeDict)) addSubframeArchive(subframeArchive.release()); else LOG(Archives, "LegacyWebArchive - Invalid subframe archive skipped"); } } return true; }