// This test checks score calculations are correct. TEST_F(DocumentStatisticsCollectorTest, CountScore) { setHtmlInnerHTML( "<p class='menu' id='article'>1</p>" // textContentLength = 1 "<ul><li><p>12</p></li></ul>" // textContentLength = 2, skipped because // under li "<p class='menu'>123</p>" // textContentLength = 3, skipped because // unlikelyCandidates "<p>" "12345678901234567890123456789012345678901234567890" "12345678901234567890123456789012345678901234567890" "12345678901234567890123456789012345678901234" "</p>" // textContentLength = 144 "<p style='display:none'>12345</p>" // textContentLength = 5, skipped // because invisible "<div style='display:none'><p>123456</p></div>" // textContentLength = 6, // skipped because // invisible "<div style='visibility:hidden'><p>1234567</p></div>" // textContentLength // = 7, skipped // because // invisible "<p style='opacity:0'>12345678</p>" // textContentLength = 8, skipped // because invisible "<p><a href='#'>1234 </a>6 <b> 9</b></p>" // textContentLength = 9 "<ul><li></li><p>123456789012</p></ul>" // textContentLength = 12 ); WebDistillabilityFeatures features = DocumentStatisticsCollector::collectStatistics(document()); EXPECT_DOUBLE_EQ(features.mozScore, sqrt(144 - kParagraphLengthThreshold)); EXPECT_DOUBLE_EQ(features.mozScoreAllSqrt, 1 + sqrt(144) + sqrt(9) + sqrt(12)); EXPECT_DOUBLE_EQ(features.mozScoreAllLinear, 1 + 144 + 9 + 12); }
TEST_F(EventHandlerTest, multiClickSelectionFromTap) { setHtmlInnerHTML("<style> body { margin: 0px; } .line { display: block; width: 300px; height: 30px; } </style>" "<body contenteditable='true'><span class='line' id='line'>One Two Three</span></body>"); FrameSelection& selection = document().frame()->selection(); Node* line = document().getElementById("line")->firstChild(); TapEventBuilder singleTapEvent(IntPoint(0, 0), 1); document().frame()->eventHandler().handleGestureEvent(singleTapEvent); ASSERT_TRUE(selection.isCaret()); EXPECT_EQ(Position(line, 0), selection.start()); // Multi-tap events on editable elements should trigger selection, just // like multi-click events. TapEventBuilder doubleTapEvent(IntPoint(0, 0), 2); document().frame()->eventHandler().handleGestureEvent(doubleTapEvent); ASSERT_TRUE(selection.isRange()); EXPECT_EQ(Position(line, 0), selection.start()); if (document().frame()->editor().isSelectTrailingWhitespaceEnabled()) { EXPECT_EQ(Position(line, 4), selection.end()); EXPECT_EQ("One ", WebString(selection.selectedText()).utf8()); } else { EXPECT_EQ(Position(line, 3), selection.end()); EXPECT_EQ("One", WebString(selection.selectedText()).utf8()); } TapEventBuilder tripleTapEvent(IntPoint(0, 0), 3); document().frame()->eventHandler().handleGestureEvent(tripleTapEvent); ASSERT_TRUE(selection.isRange()); EXPECT_EQ(Position(line, 0), selection.start()); EXPECT_EQ(Position(line, 13), selection.end()); EXPECT_EQ("One Two Three", WebString(selection.selectedText()).utf8()); }
// This tests that we properly resize and re-layout pages for printing in the presence of // media queries effecting elements in a subtree layout boundary TEST_F(DocumentTest, PrintRelayout) { setHtmlInnerHTML( "<style>" " div {" " width: 100px;" " height: 100px;" " overflow: hidden;" " }" " span {" " width: 50px;" " height: 50px;" " }" " @media screen {" " span {" " width: 20px;" " }" " }" "</style>" "<p><div><span></span></div></p>"); FloatSize pageSize(400, 400); float maximumShrinkRatio = 1.6; document().frame()->setPrinting(true, pageSize, pageSize, maximumShrinkRatio); EXPECT_EQ(document().documentElement()->offsetWidth(), 400); document().frame()->setPrinting(false, FloatSize(), FloatSize(), 0); EXPECT_EQ(document().documentElement()->offsetWidth(), 800); }
TEST_F(LayoutThemeTest, ChangeFocusRingColor) { setHtmlInnerHTML("<span id=span tabIndex=0>Span</span>"); Element* span = document().getElementById(AtomicString("span")); EXPECT_NE(nullptr, span); EXPECT_NE(nullptr, span->layoutObject()); Color customColor = makeRGB(123, 145, 167); // Checking unfocused style. EXPECT_EQ(BNONE, outlineStyle(span)); EXPECT_NE(customColor, outlineColor(span)); // Do focus. document().page()->focusController().setActive(true); document().page()->focusController().setFocused(true); span->focus(); document().view()->updateAllLifecyclePhases(); // Checking focused style. EXPECT_NE(BNONE, outlineStyle(span)); EXPECT_NE(customColor, outlineColor(span)); // Change focus ring color. LayoutTheme::theme().setCustomFocusRingColor(customColor); Page::platformColorsChanged(); document().view()->updateAllLifecyclePhases(); // Check that the focus ring color is updated. EXPECT_NE(BNONE, outlineStyle(span)); EXPECT_EQ(customColor, outlineColor(span)); }
TEST_F(DocumentTest, StyleVersion) { setHtmlInnerHTML( "<style>" " .a * { color: green }" " .b .c { color: green }" "</style>" "<div id='x'><span class='c'></span></div>"); Element* element = document().getElementById("x"); EXPECT_TRUE(element); uint64_t previousStyleVersion = document().styleVersion(); element->setAttribute(blink::HTMLNames::classAttr, "notfound"); EXPECT_EQ(previousStyleVersion, document().styleVersion()); document().view()->updateAllLifecyclePhases(); previousStyleVersion = document().styleVersion(); element->setAttribute(blink::HTMLNames::classAttr, "a"); EXPECT_NE(previousStyleVersion, document().styleVersion()); document().view()->updateAllLifecyclePhases(); previousStyleVersion = document().styleVersion(); element->setAttribute(blink::HTMLNames::classAttr, "a b"); EXPECT_NE(previousStyleVersion, document().styleVersion()); }
TEST_F(EventHandlerTest, draggedSVGImagePositionTest) { setHtmlInnerHTML( "<style>" "body { margin: 0px; }" "[draggable] {" "-webkit-user-select: none; user-select: none; -webkit-user-drag: element; }" "</style>" "<div style='width: 300px; height: 100px;'>" "<svg width='500' height='500'>" "<rect x='100' y='100' width='100px' height='100px' fill='blue' draggable='true'/>" "</svg>" "</div>"); PlatformMouseEvent mouseDownEvent( IntPoint(145, 144), IntPoint(212, 282), LeftButton, PlatformEvent::MousePressed, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseMoveEvent( IntPoint(618, 298), IntPoint(685, 436), LeftButton, PlatformEvent::MouseMoved, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseMoveEvent(mouseMoveEvent); EXPECT_EQ(IntPoint(45, 44), document().frame()->eventHandler().dragDataTransferLocationForTesting()); }
TEST_F(EventHandlerTest, draggedInlinePositionTest) { setHtmlInnerHTML( "<style>" "body { margin: 0px; }" ".line { font-family: sans-serif; background: blue; width: 300px; height: 30px; font-size: 40px; margin-left: 250px; }" "</style>" "<div style='width: 300px; height: 100px;'>" "<span class='line' draggable='true'>abcd</span>" "</div>"); PlatformMouseEvent mouseDownEvent( IntPoint(262, 29), IntPoint(329, 67), LeftButton, PlatformEvent::MousePressed, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseMoveEvent( IntPoint(618, 298), IntPoint(685, 436), LeftButton, PlatformEvent::MouseMoved, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseMoveEvent(mouseMoveEvent); EXPECT_EQ(IntPoint(12, 29), document().frame()->eventHandler().dragDataTransferLocationForTesting()); }
TEST_F(EventHandlerTest, multiClickSelectionFromTapDisabledIfNotEditable) { setHtmlInnerHTML( "<style> body { margin: 0px; } .line { display: block; width: 300px; " "height: 30px; } </style>" "<span class='line' id='line'>One Two Three</span>"); FrameSelection& selection = document().frame()->selection(); Node* line = document().getElementById("line")->firstChild(); TapEventBuilder singleTapEvent(IntPoint(0, 0), 1); document().frame()->eventHandler().handleGestureEvent(singleTapEvent); ASSERT_TRUE(selection.isCaret()); EXPECT_EQ(Position(line, 0), selection.start()); // As the text is readonly, multi-tap events should not trigger selection. TapEventBuilder doubleTapEvent(IntPoint(0, 0), 2); document().frame()->eventHandler().handleGestureEvent(doubleTapEvent); ASSERT_TRUE(selection.isCaret()); EXPECT_EQ(Position(line, 0), selection.start()); TapEventBuilder tripleTapEvent(IntPoint(0, 0), 3); document().frame()->eventHandler().handleGestureEvent(tripleTapEvent); ASSERT_TRUE(selection.isCaret()); EXPECT_EQ(Position(line, 0), selection.start()); }
// This test checks non-existence of open graph articles can be recognized. TEST_F(DocumentStatisticsCollectorTest, NoOpenGraphArticle) { setHtmlInnerHTML( "<head>" " <meta property='og:type' content='movie' />" "</head>"); WebDistillabilityFeatures features = DocumentStatisticsCollector::collectStatistics(document()); EXPECT_FALSE(features.openGraph); }
// This test checks open graph articles can be recognized. TEST_F(DocumentStatisticsCollectorTest, HasOpenGraphArticle) { setHtmlInnerHTML( "<head>" // Note the case-insensitive matching of the word "article". " <meta property='og:type' content='arTiclE' />" "</head>"); WebDistillabilityFeatures features = DocumentStatisticsCollector::collectStatistics(document()); EXPECT_TRUE(features.openGraph); }
TEST_F(EventHandlerTest, dragSelectionAfterScroll) { setHtmlInnerHTML("<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: block; width: 300px; height: 30px; } </style>" "<div class='upper'></div>" "<div class='lower'>" "<span class='line'>Line 1</span><span class='line'>Line 2</span><span class='line'>Line 3</span><span class='line'>Line 4</span><span class='line'>Line 5</span>" "<span class='line'>Line 6</span><span class='line'>Line 7</span><span class='line'>Line 8</span><span class='line'>Line 9</span><span class='line'>Line 10</span>" "</div>"); FrameView* frameView = document().view(); frameView->scrollTo(DoublePoint(0, 400)); PlatformMouseEvent mouseDownEvent( IntPoint(0, 0), IntPoint(100, 200), LeftButton, PlatformEvent::MousePressed, 1, static_cast<PlatformEvent::Modifiers>(0), WTF::currentTime()); document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseMoveEvent( IntPoint(100, 50), IntPoint(200, 250), LeftButton, PlatformEvent::MouseMoved, 1, static_cast<PlatformEvent::Modifiers>(0), WTF::currentTime()); document().frame()->eventHandler().handleMouseMoveEvent(mouseMoveEvent); page().autoscrollController().animate(WTF::currentTime()); page().animator().serviceScriptedAnimations(WTF::currentTime()); PlatformMouseEvent mouseUpEvent( IntPoint(100, 50), IntPoint(200, 250), LeftButton, PlatformEvent::MouseReleased, 1, static_cast<PlatformEvent::Modifiers>(0), WTF::currentTime()); document().frame()->eventHandler().handleMouseReleaseEvent(mouseUpEvent); FrameSelection& selection = document().frame()->selection(); ASSERT_TRUE(selection.isRange()); RefPtrWillBeRawPtr<Range> range = createRange(selection.selection().toNormalizedEphemeralRange()); ASSERT_TRUE(range.get()); EXPECT_EQ("Line 1\nLine 2", range->text()); }
TEST_F(EventHandlerTest, dragSelectionAfterScroll) { setHtmlInnerHTML( "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " "block; width: 300px; height: 30px; } </style>" "<div class='upper'></div>" "<div class='lower'>" "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " "class='line'>Line 3</span><span class='line'>Line 4</span><span " "class='line'>Line 5</span>" "<span class='line'>Line 6</span><span class='line'>Line 7</span><span " "class='line'>Line 8</span><span class='line'>Line 9</span><span " "class='line'>Line 10</span>" "</div>"); FrameView* frameView = document().view(); frameView->layoutViewportScrollableArea()->setScrollOffset( ScrollOffset(0, 400), ProgrammaticScroll); PlatformMouseEvent mouseDownEvent( IntPoint(0, 0), IntPoint(100, 200), WebPointerProperties::Button::Left, PlatformEvent::MousePressed, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseMoveEvent( IntPoint(100, 50), IntPoint(200, 250), WebPointerProperties::Button::Left, PlatformEvent::MouseMoved, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseMoveEvent( mouseMoveEvent, Vector<PlatformMouseEvent>()); page().autoscrollController().animate(WTF::monotonicallyIncreasingTime()); page().animator().serviceScriptedAnimations( WTF::monotonicallyIncreasingTime()); PlatformMouseEvent mouseUpEvent( IntPoint(100, 50), IntPoint(200, 250), WebPointerProperties::Button::Left, PlatformEvent::MouseReleased, 1, static_cast<PlatformEvent::Modifiers>(0), WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseReleaseEvent(mouseUpEvent); FrameSelection& selection = document().frame()->selection(); ASSERT_TRUE(selection.isRange()); Range* range = createRange(selection.selection().toNormalizedEphemeralRange()); ASSERT_TRUE(range); EXPECT_EQ("Line 1\nLine 2", range->text()); }
// This test checks element counts are correct. TEST_F(DocumentStatisticsCollectorTest, CountElements) { setHtmlInnerHTML( "<form>" " <input type='text'>" " <input type='password'>" "</form>" "<pre></pre>" "<p><a> </a></p>" "<ul><li><p><a> </a></p></li></ul>"); WebDistillabilityFeatures features = DocumentStatisticsCollector::collectStatistics(document()); EXPECT_FALSE(features.openGraph); EXPECT_EQ(10u, features.elementCount); EXPECT_EQ(2u, features.anchorCount); EXPECT_EQ(1u, features.formCount); EXPECT_EQ(1u, features.textInputCount); EXPECT_EQ(1u, features.passwordInputCount); EXPECT_EQ(2u, features.pCount); EXPECT_EQ(1u, features.preCount); }
// This test checks saturation of score calculations is correct. TEST_F(DocumentStatisticsCollectorTest, CountScoreSaturation) { StringBuilder html; for (int i = 0; i < 10; i++) { html.append("<p>"); for (int j = 0; j < 1000; j++) { html.append("0123456789"); } html.append("</p>"); } setHtmlInnerHTML(html.toString()); WebDistillabilityFeatures features = DocumentStatisticsCollector::collectStatistics(document()); double error = 1e-5; EXPECT_NEAR(features.mozScore, 6 * sqrt(kTextContentLengthSaturation - kParagraphLengthThreshold), error); EXPECT_NEAR(features.mozScoreAllSqrt, 6 * sqrt(kTextContentLengthSaturation), error); EXPECT_NEAR(features.mozScoreAllLinear, 6 * kTextContentLengthSaturation, error); }
// This tests that we mark Frame Timing requests as dirty correctly when we // update style. TEST_F(DocumentTest, FrameTimingRelayout) { setHtmlInnerHTML( "<style>" " #div1 {" " width: 100px;" " height: 100px;" " }" "</style>" "<p><div id='div1'><span>test</span></div></p>"); EXPECT_FALSE(document().view()->frameTimingRequestsDirty()); // Just calling update should have no effect. document().updateLayoutTreeIfNeeded(); EXPECT_FALSE(document().view()->frameTimingRequestsDirty()); // Calling update with a style change should flag Frame Timing as dirty. document().setChildNeedsStyleRecalc(); document().updateLayoutTreeIfNeeded(); EXPECT_TRUE(document().view()->frameTimingRequestsDirty()); }
// Regression test for http://crbug.com/641403 to verify we use up-to-date // layout tree for dispatching "contextmenu" event. TEST_F(EventHandlerTest, sendContextMenuEventWithHover) { setHtmlInnerHTML( "<style>*:hover { color: red; }</style>" "<div>foo</div>"); document().settings()->setScriptEnabled(true); Element* script = document().createElement("script"); script->setInnerHTML( "document.addEventListener('contextmenu', event => " "event.preventDefault());"); document().body()->appendChild(script); document().updateStyleAndLayout(); document().frame()->selection().setSelection( SelectionInDOMTree::Builder() .collapse(Position(document().body(), 0)) .build()); PlatformMouseEvent mouseDownEvent( IntPoint(0, 0), IntPoint(100, 200), WebPointerProperties::Button::Right, PlatformEvent::MousePressed, 1, PlatformEvent::Modifiers::RightButtonDown, WTF::monotonicallyIncreasingTime()); EXPECT_EQ( WebInputEventResult::HandledApplication, document().frame()->eventHandler().sendContextMenuEvent(mouseDownEvent)); }