Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 | |
| 7 #include "core/frame/FrameView.h" | |
| 8 | |
| 9 #include "core/dom/Document.h" | |
| 10 #include "core/frame/FrameOwner.h" | |
| 11 #include "core/frame/LocalFrame.h" | |
| 12 #include "core/loader/EmptyClients.h" | |
| 13 #include "core/page/Page.h" | |
| 14 #include "core/testing/DummyPageHolder.h" | |
| 15 #include "platform/testing/UnitTestHelpers.h" | |
| 16 #include <gtest/gtest.h> | |
| 17 | |
| 18 namespace blink { | |
| 19 | |
| 20 class RootFrameLoaderClient; | |
| 21 | |
| 22 class MockChromeClient final : public EmptyChromeClient { | |
|
esprehn
2015/09/21 21:27:21
Can we just write a Sim test instead?
Sami
2015/09/23 18:31:07
Looks much nicer that way. Done. One minor issue w
| |
| 23 public: | |
| 24 MockChromeClient() | |
| 25 : m_didScheduleAnimation(false) { } | |
| 26 ~MockChromeClient() override { } | |
| 27 | |
| 28 void scheduleAnimation() override | |
| 29 { | |
| 30 m_didScheduleAnimation = true; | |
| 31 } | |
| 32 | |
| 33 bool animationScheduled() const | |
| 34 { | |
| 35 return m_didScheduleAnimation; | |
| 36 } | |
| 37 | |
| 38 void resetAnimationScheduled() | |
| 39 { | |
| 40 m_didScheduleAnimation = false; | |
| 41 } | |
| 42 private: | |
| 43 bool m_didScheduleAnimation; | |
| 44 }; | |
| 45 | |
| 46 class StubFrameLoaderClientWithParent final : public EmptyFrameLoaderClient { | |
| 47 public: | |
| 48 static PassOwnPtrWillBeRawPtr<StubFrameLoaderClientWithParent> create(Frame* parent) | |
| 49 { | |
| 50 return adoptPtrWillBeNoop(new StubFrameLoaderClientWithParent(parent)); | |
| 51 } | |
| 52 | |
| 53 DEFINE_INLINE_VIRTUAL_TRACE() | |
| 54 { | |
| 55 visitor->trace(m_parent); | |
| 56 EmptyFrameLoaderClient::trace(visitor); | |
| 57 } | |
| 58 | |
| 59 Frame* parent() const override { return m_parent.get(); } | |
| 60 | |
| 61 private: | |
| 62 explicit StubFrameLoaderClientWithParent(Frame* parent) | |
| 63 : m_parent(parent) | |
| 64 { | |
| 65 } | |
| 66 | |
| 67 RawPtrWillBeMember<Frame> m_parent; | |
| 68 }; | |
| 69 | |
| 70 class StubFrameOwner : public NoBaseWillBeGarbageCollectedFinalized<StubFrameOwn er>, public FrameOwner { | |
| 71 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(StubFrameOwner); | |
| 72 public: | |
| 73 static PassOwnPtrWillBeRawPtr<StubFrameOwner> create() | |
| 74 { | |
| 75 return adoptPtrWillBeNoop(new StubFrameOwner); | |
| 76 } | |
| 77 | |
| 78 DEFINE_INLINE_VIRTUAL_TRACE() { FrameOwner::trace(visitor); } | |
| 79 | |
| 80 bool isLocal() const override { return false; } | |
| 81 SandboxFlags sandboxFlags() const override { return SandboxNone; } | |
| 82 void dispatchLoad() override { } | |
| 83 void renderFallbackContent() override { } | |
| 84 }; | |
| 85 | |
| 86 class FrameViewTest : public ::testing::Test { | |
| 87 public: | |
| 88 using SecurityOriginStatus = FrameView::SecurityOriginStatus; | |
| 89 using ViewportVisibility = FrameView::ViewportVisibility; | |
| 90 | |
| 91 void SetUp() override; | |
| 92 void TearDown() override; | |
| 93 | |
| 94 LocalFrame* childFrame() const | |
| 95 { | |
| 96 return m_childFrame.get(); | |
| 97 } | |
| 98 | |
| 99 ViewportVisibility viewportVisibility(FrameView* frameView) | |
| 100 { | |
| 101 return frameView->m_viewportVisibility; | |
| 102 } | |
| 103 | |
| 104 void enableThrottling(FrameView* frameView) | |
| 105 { | |
| 106 frameView->m_viewportVisibility = ViewportVisibility::Hidden; | |
| 107 frameView->m_securityOriginStatusForThrottling = SecurityOriginStatus::I sCrossOrigin; | |
| 108 EXPECT_TRUE(frameView->shouldThrottleRenderingPipeline()); | |
| 109 } | |
| 110 | |
| 111 protected: | |
| 112 MockChromeClient m_mockChromeClient; | |
| 113 Page::PageClients m_pageClients; | |
| 114 OwnPtr<DummyPageHolder> m_dummyPageHolder; | |
| 115 RefPtrWillBePersistent<Document> m_document; | |
| 116 OwnPtrWillBePersistent<StubFrameOwner> m_frameOwner; | |
| 117 | |
| 118 OwnPtrWillBePersistent<StubFrameLoaderClientWithParent> m_childClient; | |
| 119 RefPtrWillBePersistent<LocalFrame> m_childFrame; | |
| 120 }; | |
| 121 | |
| 122 class RootFrameLoaderClient final : public EmptyFrameLoaderClient { | |
| 123 public: | |
| 124 static PassOwnPtrWillBeRawPtr<RootFrameLoaderClient> create(FrameViewTest* t estSuite) | |
| 125 { | |
| 126 return adoptPtrWillBeNoop(new RootFrameLoaderClient(testSuite)); | |
| 127 } | |
| 128 | |
| 129 Frame* firstChild() const override { return m_testSuite->childFrame(); } | |
| 130 | |
| 131 private: | |
| 132 explicit RootFrameLoaderClient(FrameViewTest* testSuite) | |
| 133 : m_testSuite(testSuite) | |
| 134 { | |
| 135 } | |
| 136 | |
| 137 FrameViewTest* m_testSuite; | |
| 138 }; | |
| 139 | |
| 140 void FrameViewTest::SetUp() | |
| 141 { | |
| 142 // Create a root frame and one child frame. The FrameLoaderClients will conn ect the frames in the frame tree. | |
| 143 fillWithEmptyClients(m_pageClients); | |
| 144 m_pageClients.chromeClient = &m_mockChromeClient; | |
| 145 OwnPtrWillBePersistent<RootFrameLoaderClient> frameLoaderClient = RootFrameL oaderClient::create(this); | |
| 146 m_dummyPageHolder = DummyPageHolder::create(IntSize(640, 480), &m_pageClient s, frameLoaderClient.release()); | |
| 147 m_document = &m_dummyPageHolder->document(); | |
| 148 m_frameOwner = StubFrameOwner::create(); | |
| 149 | |
| 150 m_childClient = StubFrameLoaderClientWithParent::create(m_document->frame()) ; | |
| 151 m_childFrame = LocalFrame::create(m_childClient.get(), m_document->frame()-> host(), m_frameOwner.get()); | |
| 152 m_childFrame->setView(FrameView::create(m_childFrame.get(), IntSize(320, 240 ))); | |
| 153 m_childFrame->init(); | |
| 154 | |
| 155 // Also hook up the frames in the FrameView tree. | |
| 156 m_document->view()->addChild(m_childFrame->view()); | |
| 157 } | |
| 158 | |
| 159 void FrameViewTest::TearDown() | |
| 160 { | |
| 161 m_document->view()->removeChild(m_childFrame->view()); | |
| 162 m_childFrame->detach(FrameDetachType::Remove); | |
| 163 m_childFrame = nullptr; | |
| 164 } | |
| 165 | |
| 166 TEST_F(FrameViewTest, viewportVisibility) | |
| 167 { | |
| 168 // Initially both frames are visible. | |
| 169 FrameView* frameView = m_document->view(); | |
| 170 FrameView* childFrameView = m_childFrame->view(); | |
| 171 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
| 172 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView)); | |
| 173 | |
| 174 // Moving the child fully outside the parent makes it invisible. | |
| 175 childFrameView->move(0, frameView->height()); | |
| 176 frameView->updateAllLifecyclePhases(); | |
| 177 frameView->updateThrottling(); | |
| 178 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
| 179 EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView)); | |
| 180 | |
| 181 // A partially visible child is considered visible. | |
| 182 childFrameView->move(-childFrameView->width() / 2, 0); | |
| 183 frameView->updateAllLifecyclePhases(); | |
| 184 frameView->updateThrottling(); | |
| 185 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
| 186 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView)); | |
| 187 } | |
| 188 | |
| 189 TEST_F(FrameViewTest, viewportVisibilityFullyClipped) | |
| 190 { | |
| 191 // A child which is fully clipped away by its ancestor should become invisib le. | |
| 192 FrameView* frameView = m_document->view(); | |
| 193 FrameView* childFrameView = m_childFrame->view(); | |
| 194 frameView->resize(0, 0); | |
| 195 frameView->updateAllLifecyclePhases(); | |
| 196 frameView->updateThrottling(); | |
| 197 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
| 198 EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView)); | |
| 199 } | |
| 200 | |
| 201 TEST_F(FrameViewTest, hiddenCrossOriginFramesAreThrottled) | |
| 202 { | |
| 203 FrameView* frameView = m_document->view(); | |
| 204 FrameView* childFrameView = m_childFrame->view(); | |
| 205 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
| 206 EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline()); | |
| 207 | |
| 208 // Just being hidden doesn't make a frame throttled. | |
| 209 childFrameView->move(0, frameView->height()); | |
| 210 frameView->updateAllLifecyclePhases(); | |
| 211 frameView->updateThrottling(); | |
| 212 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
| 213 EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline()); | |
| 214 | |
| 215 // Also making the frame cross origin enables throttling. | |
| 216 m_childFrame->securityContext()->setSecurityOrigin(SecurityOrigin::createUni que()); | |
| 217 frameView->updateThrottling(); | |
| 218 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
| 219 EXPECT_TRUE(childFrameView->shouldThrottleRenderingPipeline()); | |
| 220 } | |
| 221 | |
| 222 TEST_F(FrameViewTest, throttledLifecycleUpdate) | |
| 223 { | |
| 224 FrameView* frameView = m_document->view(); | |
| 225 FrameView* childFrameView = m_childFrame->view(); | |
| 226 enableThrottling(childFrameView); | |
| 227 | |
| 228 childFrameView->setNeedsLayout(); | |
| 229 EXPECT_TRUE(childFrameView->needsLayout()); | |
| 230 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
| 231 EXPECT_TRUE(childFrameView->needsLayout()); | |
| 232 | |
| 233 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Disal low); | |
| 234 EXPECT_FALSE(childFrameView->needsLayout()); | |
| 235 } | |
| 236 | |
| 237 TEST_F(FrameViewTest, unthrottledFrameSchedulesVisualUpdate) | |
| 238 { | |
| 239 FrameView* frameView = m_document->view(); | |
| 240 FrameView* childFrameView = m_childFrame->view(); | |
| 241 m_childFrame->securityContext()->setSecurityOrigin(SecurityOrigin::createUni que()); | |
| 242 | |
| 243 // First make the child hidden to enable throttling. | |
| 244 childFrameView->move(0, frameView->height()); | |
| 245 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
| 246 m_mockChromeClient.resetAnimationScheduled(); | |
| 247 frameView->updateThrottling(); | |
| 248 EXPECT_FALSE(m_mockChromeClient.animationScheduled()); | |
| 249 | |
| 250 // Then bring it back on-screen. This should schedule a visual update. | |
| 251 childFrameView->move(0, 0); | |
| 252 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
| 253 m_mockChromeClient.resetAnimationScheduled(); | |
| 254 frameView->updateThrottling(); | |
| 255 EXPECT_TRUE(m_mockChromeClient.animationScheduled()); | |
| 256 } | |
| 257 | |
| 258 } // namespace blink | |
| OLD | NEW |