Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/dom/Element.h" | 5 #include "core/dom/Element.h" |
| 6 | 6 |
| 7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
| 8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
| 9 #include "core/html/HTMLHtmlElement.h" | 9 #include "core/html/HTMLHtmlElement.h" |
| 10 #include "core/layout/LayoutBoxModelObject.h" | |
| 11 #include "core/paint/PaintLayer.h" | |
| 10 #include "core/testing/DummyPageHolder.h" | 12 #include "core/testing/DummyPageHolder.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 12 #include <memory> | 14 #include <memory> |
| 13 | 15 |
| 14 namespace blink { | 16 namespace blink { |
| 15 | 17 |
| 16 TEST(ElementTest, SupportsFocus) { | 18 TEST(ElementTest, SupportsFocus) { |
| 17 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | 19 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); |
| 18 Document& document = pageHolder->document(); | 20 Document& document = pageHolder->document(); |
| 19 DCHECK(isHTMLHtmlElement(document.documentElement())); | 21 DCHECK(isHTMLHtmlElement(document.documentElement())); |
| 20 document.setDesignMode("on"); | 22 document.setDesignMode("on"); |
| 21 document.view()->updateAllLifecyclePhases(); | 23 document.view()->updateAllLifecyclePhases(); |
| 22 EXPECT_TRUE(document.documentElement()->supportsFocus()) | 24 EXPECT_TRUE(document.documentElement()->supportsFocus()) |
| 23 << "<html> with designMode=on should be focusable."; | 25 << "<html> with designMode=on should be focusable."; |
| 24 } | 26 } |
| 25 | 27 |
| 28 // Verifies that calling getBoundingClientRect cleans compositor inputs. | |
| 29 // Cleaning the compositor inputs is required so that position:sticky elements | |
| 30 // and their descendants have the correct location. | |
| 31 TEST(ElementTest, GetBoundingClientRectUpdatesCompositorInputs) { | |
| 32 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
| 33 Document& document = pageHolder->document(); | |
| 34 | |
| 35 document.view()->updateAllLifecyclePhases(); | |
| 36 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
| 37 | |
| 38 document.body()->setInnerHTML("<div id='test'></div>"); | |
| 39 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 40 document.lifecycle().state()); | |
| 41 | |
| 42 document.body()->getBoundingClientRect(); | |
| 43 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 44 } | |
| 45 | |
| 46 // Verifies that calling scrollIntoView* cleans compositor inputs. Cleaning the | |
| 47 // compositor inputs is required so that position:sticky elements and their | |
| 48 // descendants have the correct location. | |
| 49 TEST(ElementTest, ScrollIntoViewUpdatesCompositorInputs) { | |
| 50 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
| 51 Document& document = pageHolder->document(); | |
| 52 | |
| 53 document.view()->updateAllLifecyclePhases(); | |
| 54 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
| 55 | |
| 56 document.body()->setInnerHTML("<div id='test'></div>"); | |
| 57 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 58 document.lifecycle().state()); | |
| 59 | |
| 60 document.body()->scrollIntoView(); | |
| 61 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 62 | |
| 63 document.body()->setInnerHTML("<div id='test2'></div>"); | |
| 64 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 65 document.lifecycle().state()); | |
| 66 | |
| 67 document.body()->scrollIntoViewIfNeeded(); | |
| 68 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 69 } | |
| 70 | |
| 71 // Verifies that calling offsetTop/offsetLeft cleans compositor inputs. | |
| 72 // Cleaning the compositor inputs is required so that position:sticky elements | |
| 73 // and their descendants have the correct location. | |
| 74 TEST(ElementTest, OffsetTopAndLeftUpdateCompositorInputs) { | |
| 75 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
| 76 Document& document = pageHolder->document(); | |
| 77 | |
| 78 document.view()->updateAllLifecyclePhases(); | |
| 79 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
| 80 | |
| 81 document.body()->setInnerHTML("<div id='test'></div>"); | |
| 82 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 83 document.lifecycle().state()); | |
| 84 | |
| 85 document.body()->offsetTop(); | |
| 86 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 87 | |
| 88 document.body()->setInnerHTML("<div id='test2'></div>"); | |
| 89 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 90 document.lifecycle().state()); | |
| 91 | |
| 92 document.body()->offsetLeft(); | |
| 93 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 94 } | |
| 95 | |
| 96 TEST(ElementTest, OffsetTopAndLeftCorrectForStickyElementsAfterInsertion) { | |
| 97 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
| 98 Document& document = pageHolder->document(); | |
| 99 | |
| 100 document.body()->setInnerHTML( | |
| 101 "<style>body { margin: 0 }" | |
| 102 "#scroller { overflow: scroll; height: 100px; width: 100px; }" | |
| 103 "#sticky { height: 25px; position: sticky; top: 0; left: 25px }" | |
|
flackr
2017/01/24 22:47:16
nit: semicolon after 25px
smcgruer
2017/01/25 20:51:57
Done.
| |
| 104 "#padding { height: 500px; width: 300px; }</style>" | |
| 105 "<div id='scroller'><div id='writer'></div><div id='sticky'></div>" | |
| 106 "<div id='padding'></div></div>"); | |
| 107 document.view()->updateAllLifecyclePhases(); | |
| 108 | |
| 109 Element* scroller = document.getElementById("scroller"); | |
| 110 Element* writer = document.getElementById("writer"); | |
| 111 Element* sticky = document.getElementById("sticky"); | |
| 112 | |
| 113 ASSERT_TRUE(scroller); | |
| 114 ASSERT_TRUE(writer); | |
| 115 ASSERT_TRUE(sticky); | |
| 116 | |
| 117 scroller->scrollTo(0, 200.0); | |
| 118 | |
| 119 // After scrolling, the position:sticky element should be offset to stay at | |
| 120 // the top of the viewport. | |
| 121 EXPECT_EQ(scroller->scrollTop(), sticky->offsetTop()); | |
| 122 | |
| 123 // Insert a new <div> above the sticky. This will dirty layout. | |
| 124 writer->setInnerHTML("<div style='height: 100px;'></div>"); | |
| 125 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 126 document.lifecycle().state()); | |
| 127 | |
| 128 // Querying the new position of the sticky should now cause both layout and | |
| 129 // compositing inputs to be clean and should return the correct position. | |
| 130 // Additionally, repeated calls to offsetTop should give the same value. | |
| 131 int offsetTop = sticky->offsetTop(); | |
| 132 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 133 EXPECT_FALSE( | |
| 134 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
| 135 EXPECT_EQ(scroller->scrollTop(), sticky->offsetTop()); | |
| 136 EXPECT_EQ(offsetTop, sticky->offsetTop()); | |
|
flackr
2017/01/24 22:47:16
Hm, I'm not sure what case I was worried about wit
smcgruer
2017/01/25 20:51:57
Ok, removed.
| |
| 137 | |
| 138 scroller->scrollTo(50.0, 0); | |
| 139 | |
| 140 // After scrolling, the position:sticky element should be offset to stay 25 | |
| 141 // pixels from the left of the viewport. | |
| 142 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->offsetLeft()); | |
| 143 | |
| 144 // Insert a new <div> above the sticky. This will dirty layout. | |
| 145 writer->setInnerHTML("<div style='width: 700px;'></div>"); | |
| 146 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
| 147 document.lifecycle().state()); | |
| 148 | |
| 149 // Again, querying the position should cause layout and compositing clean, and | |
| 150 // should return the correct position repeatedly. | |
| 151 int offsetLeft = sticky->offsetLeft(); | |
| 152 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
| 153 EXPECT_FALSE( | |
| 154 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
| 155 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->offsetLeft()); | |
| 156 EXPECT_EQ(offsetLeft, sticky->offsetLeft()); | |
| 157 } | |
| 158 | |
| 26 } // namespace blink | 159 } // namespace blink |
| OLD | NEW |